xref: /btstack/src/btstack_util.c (revision ed7a067cb20201ce77a97129882c83d8f45c7ce8)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "btstack_util.c"
39 
40 /*
41  *  General utility functions
42  */
43 
44 #include "btstack_config.h"
45 #include "btstack_debug.h"
46 #include "btstack_util.h"
47 
48 #ifdef _MSC_VER
49 #include <intrin.h>
50 #include <windows.h>
51 #endif
52 
53 #ifdef ENABLE_PRINTF_HEXDUMP
54 #include <stdio.h>
55 #endif
56 
57 #include <string.h>
58 
59 /**
60  * @brief Compare two Bluetooth addresses
61  * @param a
62  * @param b
63  * @return 0 if equal
64  */
65 int bd_addr_cmp(const bd_addr_t a, const bd_addr_t b){
66     return memcmp(a,b, BD_ADDR_LEN);
67 }
68 
69 /**
70  * @brief Copy Bluetooth address
71  * @param dest
72  * @param src
73  */
74 void bd_addr_copy(bd_addr_t dest, const bd_addr_t src){
75     (void)memcpy(dest, src, BD_ADDR_LEN);
76 }
77 
78 uint16_t little_endian_read_16(const uint8_t * buffer, int position){
79     return (uint16_t)(((uint16_t) buffer[position]) | (((uint16_t)buffer[position+1]) << 8));
80 }
81 uint32_t little_endian_read_24(const uint8_t * buffer, int position){
82     return ((uint32_t) buffer[position]) | (((uint32_t)buffer[position+1]) << 8) | (((uint32_t)buffer[position+2]) << 16);
83 }
84 uint32_t little_endian_read_32(const uint8_t * buffer, int position){
85     return ((uint32_t) buffer[position]) | (((uint32_t)buffer[position+1]) << 8) | (((uint32_t)buffer[position+2]) << 16) | (((uint32_t) buffer[position+3]) << 24);
86 }
87 
88 void little_endian_store_16(uint8_t * buffer, uint16_t position, uint16_t value){
89     uint16_t pos = position;
90     buffer[pos++] = (uint8_t)value;
91     buffer[pos++] = (uint8_t)(value >> 8);
92 }
93 
94 void little_endian_store_24(uint8_t * buffer, uint16_t position, uint32_t value){
95     uint16_t pos = position;
96     buffer[pos++] = (uint8_t)(value);
97     buffer[pos++] = (uint8_t)(value >> 8);
98     buffer[pos++] = (uint8_t)(value >> 16);
99 }
100 
101 void little_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value){
102     uint16_t pos = position;
103     buffer[pos++] = (uint8_t)(value);
104     buffer[pos++] = (uint8_t)(value >> 8);
105     buffer[pos++] = (uint8_t)(value >> 16);
106     buffer[pos++] = (uint8_t)(value >> 24);
107 }
108 
109 uint32_t big_endian_read_16(const uint8_t * buffer, int position) {
110     return (uint16_t)(((uint16_t) buffer[position+1]) | (((uint16_t)buffer[position]) << 8));
111 }
112 
113 uint32_t big_endian_read_24(const uint8_t * buffer, int position) {
114     return ( ((uint32_t)buffer[position+2]) | (((uint32_t)buffer[position+1]) << 8) | (((uint32_t) buffer[position]) << 16));
115 }
116 
117 uint32_t big_endian_read_32(const uint8_t * buffer, int position) {
118     return ((uint32_t) buffer[position+3]) | (((uint32_t)buffer[position+2]) << 8) | (((uint32_t)buffer[position+1]) << 16) | (((uint32_t) buffer[position]) << 24);
119 }
120 
121 void big_endian_store_16(uint8_t * buffer, uint16_t position, uint16_t value){
122     uint16_t pos = position;
123     buffer[pos++] = (uint8_t)(value >> 8);
124     buffer[pos++] = (uint8_t)(value);
125 }
126 
127 void big_endian_store_24(uint8_t * buffer, uint16_t position, uint32_t value){
128     uint16_t pos = position;
129     buffer[pos++] = (uint8_t)(value >> 16);
130     buffer[pos++] = (uint8_t)(value >> 8);
131     buffer[pos++] = (uint8_t)(value);
132 }
133 
134 void big_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value){
135     uint16_t pos = position;
136     buffer[pos++] = (uint8_t)(value >> 24);
137     buffer[pos++] = (uint8_t)(value >> 16);
138     buffer[pos++] = (uint8_t)(value >> 8);
139     buffer[pos++] = (uint8_t)(value);
140 }
141 
142 // general swap/endianess utils
143 void reverse_bytes(const uint8_t * src, uint8_t * dest, int len){
144     int i;
145     for (i = 0; i < len; i++)
146         dest[len - 1 - i] = src[i];
147 }
148 void reverse_24(const uint8_t * src, uint8_t * dest){
149     reverse_bytes(src, dest, 3);
150 }
151 void reverse_48(const uint8_t * src, uint8_t * dest){
152     reverse_bytes(src, dest, 6);
153 }
154 void reverse_56(const uint8_t * src, uint8_t * dest){
155     reverse_bytes(src, dest, 7);
156 }
157 void reverse_64(const uint8_t * src, uint8_t * dest){
158     reverse_bytes(src, dest, 8);
159 }
160 void reverse_128(const uint8_t * src, uint8_t * dest){
161     reverse_bytes(src, dest, 16);
162 }
163 void reverse_256(const uint8_t * src, uint8_t * dest){
164     reverse_bytes(src, dest, 32);
165 }
166 
167 void reverse_bd_addr(const bd_addr_t src, bd_addr_t dest){
168     reverse_bytes(src, dest, 6);
169 }
170 
171 uint32_t btstack_min(uint32_t a, uint32_t b){
172     return (a < b) ? a : b;
173 }
174 
175 uint32_t btstack_max(uint32_t a, uint32_t b){
176     return (a > b) ? a : b;
177 }
178 
179 /**
180  * @brief Calculate delta between two uint32_t points in time
181  * @return time_a - time_b - result > 0 if time_a is newer than time_b
182  */
183 int32_t btstack_time_delta(uint32_t time_a, uint32_t time_b){
184     return (int32_t)(time_a - time_b);
185 }
186 
187 /**
188  * @brief Calculate delta between two uint16_t points in time
189  * @return time_a - time_b - result > 0 if time_a is newer than time_b
190  */
191 int16_t btstack_time16_delta(uint16_t time_a, uint16_t time_b){
192     return (int16_t)(time_a - time_b);
193 }
194 
195 char char_for_nibble(int nibble){
196 
197     static const char * char_to_nibble = "0123456789ABCDEF";
198 
199     if (nibble < 16){
200         return char_to_nibble[nibble];
201     } else {
202         return '?';
203     }
204 }
205 
206 static inline char char_for_high_nibble(int value){
207     return char_for_nibble((value >> 4) & 0x0f);
208 }
209 
210 static inline char char_for_low_nibble(int value){
211     return char_for_nibble(value & 0x0f);
212 }
213 
214 
215 int nibble_for_char(char c){
216     if ((c >= '0') && (c <= '9')) return c - '0';
217     if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10;
218     if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
219     return -1;
220 }
221 
222 #ifdef ENABLE_PRINTF_HEXDUMP
223 void printf_hexdump(const void * data, int size){
224     char buffer[4];
225     buffer[2] = ' ';
226     buffer[3] =  0;
227     const uint8_t * ptr = (const uint8_t *) data;
228     while (size > 0){
229         uint8_t byte = *ptr++;
230         buffer[0] = char_for_high_nibble(byte);
231         buffer[1] = char_for_low_nibble(byte);
232         printf("%s", buffer);
233         size--;
234     }
235     printf("\n");
236 }
237 #endif
238 
239 #if defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG)
240 static void log_hexdump(int level, const void * data, int size){
241 #define ITEMS_PER_LINE 16
242 // template '0x12, '
243 #define BYTES_PER_BYTE  6
244     char buffer[BYTES_PER_BYTE*ITEMS_PER_LINE+1];
245     int i, j;
246     j = 0;
247     for (i=0; i<size;i++){
248 
249         // help static analyzer proof that j stays within bounds
250         if (j > (BYTES_PER_BYTE * (ITEMS_PER_LINE-1))){
251             j = 0;
252         }
253 
254         uint8_t byte = ((uint8_t *)data)[i];
255         buffer[j++] = '0';
256         buffer[j++] = 'x';
257         buffer[j++] = char_for_high_nibble(byte);
258         buffer[j++] = char_for_low_nibble(byte);
259         buffer[j++] = ',';
260         buffer[j++] = ' ';
261 
262         if (j >= (BYTES_PER_BYTE * ITEMS_PER_LINE) ){
263             buffer[j] = 0;
264             HCI_DUMP_LOG(level, "%s", buffer);
265             j = 0;
266         }
267     }
268     if (j != 0){
269         buffer[j] = 0;
270         HCI_DUMP_LOG(level, "%s", buffer);
271     }
272 }
273 #endif
274 
275 void log_debug_hexdump(const void * data, int size){
276 #ifdef ENABLE_LOG_DEBUG
277     log_hexdump(HCI_DUMP_LOG_LEVEL_DEBUG, data, size);
278 #else
279     UNUSED(data);   // ok: no code
280     UNUSED(size);   // ok: no code
281 #endif
282 }
283 
284 void log_info_hexdump(const void * data, int size){
285 #ifdef ENABLE_LOG_INFO
286     log_hexdump(HCI_DUMP_LOG_LEVEL_INFO, data, size);
287 #else
288     UNUSED(data);   // ok: no code
289     UNUSED(size);   // ok: no code
290 #endif
291 }
292 
293 void log_info_key(const char * name, sm_key_t key){
294 #ifdef ENABLE_LOG_INFO
295     char buffer[16*2+1];
296     int i;
297     int j = 0;
298     for (i=0; i<16;i++){
299         uint8_t byte = key[i];
300         buffer[j++] = char_for_high_nibble(byte);
301         buffer[j++] = char_for_low_nibble(byte);
302     }
303     buffer[j] = 0;
304     log_info("%-6s %s", name, buffer);
305 #else
306     UNUSED(name);
307     (void)key;
308 #endif
309 }
310 
311 // UUIDs are stored in big endian, similar to bd_addr_t
312 
313 // Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
314 const uint8_t bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
315     0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
316 
317 void uuid_add_bluetooth_prefix(uint8_t * uuid128, uint32_t short_uuid){
318     (void)memcpy(uuid128, bluetooth_base_uuid, 16);
319     big_endian_store_32(uuid128, 0, short_uuid);
320 }
321 
322 int uuid_has_bluetooth_prefix(const uint8_t * uuid128){
323     return memcmp(&uuid128[4], &bluetooth_base_uuid[4], 12) == 0;
324 }
325 
326 static char uuid128_to_str_buffer[32+4+1];
327 char * uuid128_to_str(const uint8_t * uuid){
328     int i;
329     int j = 0;
330     // after 4, 6, 8, and 10 bytes = XYXYXYXY-XYXY-XYXY-XYXY-XYXYXYXYXYXY, there's a dash
331     const int dash_locations = (1<<3) | (1<<5) | (1<<7) | (1<<9);
332     for (i=0;i<16;i++){
333         uint8_t byte = uuid[i];
334         uuid128_to_str_buffer[j++] = char_for_high_nibble(byte);
335         uuid128_to_str_buffer[j++] = char_for_low_nibble(byte);
336         if (dash_locations & (1<<i)){
337             uuid128_to_str_buffer[j++] = '-';
338         }
339     }
340     return uuid128_to_str_buffer;
341 }
342 
343 static char bd_addr_to_str_buffer[6*3];  // 12:45:78:01:34:67\0
344 char * bd_addr_to_str_with_delimiter(const bd_addr_t addr, char delimiter){
345     char * p = bd_addr_to_str_buffer;
346     int i;
347     for (i = 0; i < 6 ; i++) {
348         uint8_t byte = addr[i];
349         *p++ = char_for_high_nibble(byte);
350         *p++ = char_for_low_nibble(byte);
351         *p++ = delimiter;
352     }
353     *--p = 0;
354     return (char *) bd_addr_to_str_buffer;
355 }
356 
357 char * bd_addr_to_str(const bd_addr_t addr){
358     return bd_addr_to_str_with_delimiter(addr, ':');
359 }
360 
361 void btstack_replace_bd_addr_placeholder(uint8_t * buffer, uint16_t size, const bd_addr_t address){
362     const int bd_addr_string_len = 17;
363     uint16_t i = 0;
364     while ((i + bd_addr_string_len) <= size){
365         if (memcmp(&buffer[i], "00:00:00:00:00:00", bd_addr_string_len)) {
366             i++;
367             continue;
368         }
369         // set address
370         (void)memcpy(&buffer[i], bd_addr_to_str(address), bd_addr_string_len);
371         i += bd_addr_string_len;
372     }
373 }
374 
375 static int scan_hex_byte(const char * byte_string){
376     int upper_nibble = nibble_for_char(byte_string[0]);
377     if (upper_nibble < 0) return -1;
378     int lower_nibble = nibble_for_char(byte_string[1]);
379     if (lower_nibble < 0) return -1;
380     return (upper_nibble << 4) | lower_nibble;
381 }
382 
383 int sscanf_bd_addr(const char * addr_string, bd_addr_t addr){
384     const char * the_string = addr_string;
385     uint8_t buffer[BD_ADDR_LEN];
386     int result = 0;
387     int i;
388     for (i = 0; i < BD_ADDR_LEN; i++) {
389         int single_byte = scan_hex_byte(the_string);
390         if (single_byte < 0) break;
391         the_string += 2;
392         buffer[i] = (uint8_t)single_byte;
393         // don't check separator after last byte
394         if (i == (BD_ADDR_LEN - 1)) {
395             result = 1;
396             break;
397         }
398         // skip supported separators
399         char next_char = *the_string;
400         if ((next_char == ':') || (next_char == '-') || (next_char == ' ')) {
401             the_string++;
402         }
403     }
404 
405     if (result != 0){
406         bd_addr_copy(addr, buffer);
407     }
408 	return result;
409 }
410 
411 uint32_t btstack_atoi(const char * str){
412     const char * the_string = str;
413     uint32_t val = 0;
414     while (true){
415         char chr = *the_string++;
416         if (!chr || (chr < '0') || (chr > '9'))
417             return val;
418         val = (val * 10u) + (uint8_t)(chr - '0');
419     }
420 }
421 
422 int string_len_for_uint32(uint32_t i){
423     if (i <         10) return 1;
424     if (i <        100) return 2;
425     if (i <       1000) return 3;
426     if (i <      10000) return 4;
427     if (i <     100000) return 5;
428     if (i <    1000000) return 6;
429     if (i <   10000000) return 7;
430     if (i <  100000000) return 8;
431     if (i < 1000000000) return 9;
432     return 10;
433 }
434 
435 int count_set_bits_uint32(uint32_t x){
436     uint32_t v = x;
437     v = (v & 0x55555555) + ((v >> 1)  & 0x55555555U);
438     v = (v & 0x33333333) + ((v >> 2)  & 0x33333333U);
439     v = (v & 0x0F0F0F0F) + ((v >> 4)  & 0x0F0F0F0FU);
440     v = (v & 0x00FF00FF) + ((v >> 8)  & 0x00FF00FFU);
441     v = (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFFU);
442     return v;
443 }
444 
445 uint8_t btstack_clz(uint32_t value) {
446 #if defined(__GNUC__) || defined (__clang__)
447     // use gcc/clang intrinsic
448     return (uint8_t) __builtin_clz(value);
449 #elif defined(_MSC_VER)
450     // use MSVC intrinsic
451     DWORD leading_zero = 0;
452     if (_BitScanReverse( &leading_zero, value )){
453 		return (uint8_t)(31 - leading_zero);
454     } else {
455         return 32;
456     }
457 #else
458     // divide-and-conquer implementation for 32-bit integers
459     if (x == 0) return 32;
460     uint8_t r = 0;
461     if ((x & 0xffff0000u) == 0) {
462         x <<= 16;
463         r += 16;
464     }
465     if ((x & 0xff000000u) == 0) {
466         x <<= 8;
467         r += 8;
468     }
469     if ((x & 0xf0000000u) == 0) {
470         x <<= 4;
471         r += 4;
472     }
473     if ((x & 0xc0000000u) == 0) {
474         x <<= 2;
475         r += 2;
476     }
477     if ((x & 0x80000000u) == 0) {
478         x <<= 1;
479         r += 1;
480     }
481     return r;
482 #endif
483 }
484 
485 /*
486  * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
487  */
488 
489 #define CRC8_INIT  0xFF          // Initial FCS value
490 #define CRC8_OK    0xCF          // Good final FCS value
491 
492 static const uint8_t crc8table[256] = {    /* reversed, 8-bit, poly=0x07 */
493     0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
494     0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
495     0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
496     0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
497     0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
498     0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
499     0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
500     0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
501     0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
502     0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
503     0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
504     0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
505     0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
506     0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
507     0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
508     0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
509 };
510 
511 /*-----------------------------------------------------------------------------------*/
512 static uint8_t crc8(uint8_t *data, uint16_t len){
513     uint16_t count;
514     uint8_t crc = CRC8_INIT;
515     for (count = 0; count < len; count++){
516         crc = crc8table[crc ^ data[count]];
517     }
518     return crc;
519 }
520 
521 /*-----------------------------------------------------------------------------------*/
522 uint8_t btstack_crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum){
523     uint8_t crc;
524     crc = crc8(data, len);
525     crc = crc8table[crc ^ check_sum];
526     if (crc == CRC8_OK){
527         return 0;               /* Valid */
528     } else {
529         return 1;               /* Failed */
530     }
531 }
532 
533 /*-----------------------------------------------------------------------------------*/
534 uint8_t btstack_crc8_calc(uint8_t *data, uint16_t len){
535     /* Ones complement */
536     return 0xFFu - crc8(data, len);
537 }
538 
539 uint16_t btstack_next_cid_ignoring_zero(uint16_t current_cid){
540     uint16_t next_cid;
541     if (current_cid == 0xffff) {
542         next_cid = 1;
543     } else {
544         next_cid = current_cid + 1;
545     }
546     return next_cid;
547 }
548 
549 uint16_t btstack_strcpy(char * dst, uint16_t dst_size, const char * src){
550     uint16_t bytes_to_copy = btstack_min( dst_size - 1, strlen(src));
551     (void) memcpy(dst, src, bytes_to_copy);
552     dst[dst_size-1] = 0;
553     return bytes_to_copy + 1;
554 }
555 
556 void btstack_strcat(char * dst, uint16_t dst_size, const char * src){
557     uint16_t src_len = (uint16_t) strlen(src);
558     uint16_t dst_len = (uint16_t) strlen(dst);
559     uint16_t bytes_to_copy = btstack_min( src_len, dst_size - dst_len - 1);
560     (void) memcpy( &dst[dst_len], src, bytes_to_copy);
561     dst[dst_len + bytes_to_copy] = 0;
562 }
563 
564 uint16_t btstack_virtual_memcpy(
565     const uint8_t * field_data, uint16_t field_len, uint16_t field_offset, // position of field in complete data block
566     uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){
567 
568     uint16_t after_buffer = buffer_offset + buffer_size ;
569     // bail before buffer
570     if ((field_offset + field_len) < buffer_offset){
571         return 0;
572     }
573     // bail after buffer
574     if (field_offset >= after_buffer){
575         return 0;
576     }
577     // calc overlap
578     uint16_t bytes_to_copy = field_len;
579 
580     uint16_t skip_at_start = 0;
581     if (field_offset < buffer_offset){
582         skip_at_start = buffer_offset - field_offset;
583         bytes_to_copy -= skip_at_start;
584     }
585 
586     uint16_t skip_at_end = 0;
587     if ((field_offset + field_len) > after_buffer){
588         skip_at_end = (field_offset + field_len) - after_buffer;
589         bytes_to_copy -= skip_at_end;
590     }
591 
592     btstack_assert((skip_at_end + skip_at_start) <= field_len);
593     btstack_assert(bytes_to_copy <= field_len);
594 
595     memcpy(&buffer[(field_offset + skip_at_start) - buffer_offset], &field_data[skip_at_start], bytes_to_copy);
596     return bytes_to_copy;
597 }
598