xref: /btstack/src/btstack_util.c (revision e3ba22907f903f11cd12321c31e7936b8dd1157e)
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 bool btstack_is_null(const uint8_t * buffer, uint16_t size){
172     uint16_t i;
173     for (i=0; i < size ; i++){
174         if (buffer[i] != 0) {
175             return false;
176         }
177     }
178     return true;
179 }
180 
181 uint32_t btstack_min(uint32_t a, uint32_t b){
182     return (a < b) ? a : b;
183 }
184 
185 uint32_t btstack_max(uint32_t a, uint32_t b){
186     return (a > b) ? a : b;
187 }
188 
189 /**
190  * @brief Calculate delta between two uint32_t points in time
191  * @return time_a - time_b - result > 0 if time_a is newer than time_b
192  */
193 int32_t btstack_time_delta(uint32_t time_a, uint32_t time_b){
194     return (int32_t)(time_a - time_b);
195 }
196 
197 /**
198  * @brief Calculate delta between two uint16_t points in time
199  * @return time_a - time_b - result > 0 if time_a is newer than time_b
200  */
201 int16_t btstack_time16_delta(uint16_t time_a, uint16_t time_b){
202     return (int16_t)(time_a - time_b);
203 }
204 
205 char char_for_nibble(int nibble){
206 
207     static const char * char_to_nibble = "0123456789ABCDEF";
208 
209     if (nibble < 16){
210         return char_to_nibble[nibble];
211     } else {
212         return '?';
213     }
214 }
215 
216 static inline char char_for_high_nibble(int value){
217     return char_for_nibble((value >> 4) & 0x0f);
218 }
219 
220 static inline char char_for_low_nibble(int value){
221     return char_for_nibble(value & 0x0f);
222 }
223 
224 
225 int nibble_for_char(char c){
226     if ((c >= '0') && (c <= '9')) return c - '0';
227     if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10;
228     if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
229     return -1;
230 }
231 
232 #ifdef ENABLE_PRINTF_HEXDUMP
233 void printf_hexdump(const void * data, int size){
234     char buffer[4];
235     buffer[2] = ' ';
236     buffer[3] =  0;
237     const uint8_t * ptr = (const uint8_t *) data;
238     while (size > 0){
239         uint8_t byte = *ptr++;
240         buffer[0] = char_for_high_nibble(byte);
241         buffer[1] = char_for_low_nibble(byte);
242         printf("%s", buffer);
243         size--;
244     }
245     printf("\n");
246 }
247 #endif
248 
249 #if defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG)
250 static void log_hexdump(int level, const void * data, int size){
251 #define ITEMS_PER_LINE 16
252 // template '0x12, '
253 #define BYTES_PER_BYTE  6
254     char buffer[BYTES_PER_BYTE*ITEMS_PER_LINE+1];
255     int i, j;
256     j = 0;
257     for (i=0; i<size;i++){
258 
259         // help static analyzer proof that j stays within bounds
260         if (j > (BYTES_PER_BYTE * (ITEMS_PER_LINE-1))){
261             j = 0;
262         }
263 
264         uint8_t byte = ((uint8_t *)data)[i];
265         buffer[j++] = '0';
266         buffer[j++] = 'x';
267         buffer[j++] = char_for_high_nibble(byte);
268         buffer[j++] = char_for_low_nibble(byte);
269         buffer[j++] = ',';
270         buffer[j++] = ' ';
271 
272         if (j >= (BYTES_PER_BYTE * ITEMS_PER_LINE) ){
273             buffer[j] = 0;
274             HCI_DUMP_LOG(level, "%s", buffer);
275             j = 0;
276         }
277     }
278     if (j != 0){
279         buffer[j] = 0;
280         HCI_DUMP_LOG(level, "%s", buffer);
281     }
282 }
283 #endif
284 
285 void log_debug_hexdump(const void * data, int size){
286 #ifdef ENABLE_LOG_DEBUG
287     log_hexdump(HCI_DUMP_LOG_LEVEL_DEBUG, data, size);
288 #else
289     UNUSED(data);   // ok: no code
290     UNUSED(size);   // ok: no code
291 #endif
292 }
293 
294 void log_info_hexdump(const void * data, int size){
295 #ifdef ENABLE_LOG_INFO
296     log_hexdump(HCI_DUMP_LOG_LEVEL_INFO, data, size);
297 #else
298     UNUSED(data);   // ok: no code
299     UNUSED(size);   // ok: no code
300 #endif
301 }
302 
303 void log_info_key(const char * name, sm_key_t key){
304 #ifdef ENABLE_LOG_INFO
305     char buffer[16*2+1];
306     int i;
307     int j = 0;
308     for (i=0; i<16;i++){
309         uint8_t byte = key[i];
310         buffer[j++] = char_for_high_nibble(byte);
311         buffer[j++] = char_for_low_nibble(byte);
312     }
313     buffer[j] = 0;
314     log_info("%-6s %s", name, buffer);
315 #else
316     UNUSED(name);
317     (void)key;
318 #endif
319 }
320 
321 // UUIDs are stored in big endian, similar to bd_addr_t
322 
323 // Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
324 const uint8_t bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
325     0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
326 
327 void uuid_add_bluetooth_prefix(uint8_t * uuid128, uint32_t short_uuid){
328     (void)memcpy(uuid128, bluetooth_base_uuid, 16);
329     big_endian_store_32(uuid128, 0, short_uuid);
330 }
331 
332 int uuid_has_bluetooth_prefix(const uint8_t * uuid128){
333     return memcmp(&uuid128[4], &bluetooth_base_uuid[4], 12) == 0;
334 }
335 
336 static char uuid128_to_str_buffer[32+4+1];
337 char * uuid128_to_str(const uint8_t * uuid){
338     int i;
339     int j = 0;
340     // after 4, 6, 8, and 10 bytes = XYXYXYXY-XYXY-XYXY-XYXY-XYXYXYXYXYXY, there's a dash
341     const int dash_locations = (1<<3) | (1<<5) | (1<<7) | (1<<9);
342     for (i=0;i<16;i++){
343         uint8_t byte = uuid[i];
344         uuid128_to_str_buffer[j++] = char_for_high_nibble(byte);
345         uuid128_to_str_buffer[j++] = char_for_low_nibble(byte);
346         if (dash_locations & (1<<i)){
347             uuid128_to_str_buffer[j++] = '-';
348         }
349     }
350     return uuid128_to_str_buffer;
351 }
352 
353 static char bd_addr_to_str_buffer[6*3];  // 12:45:78:01:34:67\0
354 char * bd_addr_to_str_with_delimiter(const bd_addr_t addr, char delimiter){
355     char * p = bd_addr_to_str_buffer;
356     int i;
357     for (i = 0; i < 6 ; i++) {
358         uint8_t byte = addr[i];
359         *p++ = char_for_high_nibble(byte);
360         *p++ = char_for_low_nibble(byte);
361         *p++ = delimiter;
362     }
363     *--p = 0;
364     return (char *) bd_addr_to_str_buffer;
365 }
366 
367 char * bd_addr_to_str(const bd_addr_t addr){
368     return bd_addr_to_str_with_delimiter(addr, ':');
369 }
370 
371 void btstack_replace_bd_addr_placeholder(uint8_t * buffer, uint16_t size, const bd_addr_t address){
372     const int bd_addr_string_len = 17;
373     uint16_t i = 0;
374     while ((i + bd_addr_string_len) <= size){
375         if (memcmp(&buffer[i], "00:00:00:00:00:00", bd_addr_string_len)) {
376             i++;
377             continue;
378         }
379         // set address
380         (void)memcpy(&buffer[i], bd_addr_to_str(address), bd_addr_string_len);
381         i += bd_addr_string_len;
382     }
383 }
384 
385 static int scan_hex_byte(const char * byte_string){
386     int upper_nibble = nibble_for_char(byte_string[0]);
387     if (upper_nibble < 0) return -1;
388     int lower_nibble = nibble_for_char(byte_string[1]);
389     if (lower_nibble < 0) return -1;
390     return (upper_nibble << 4) | lower_nibble;
391 }
392 
393 int sscanf_bd_addr(const char * addr_string, bd_addr_t addr){
394     const char * the_string = addr_string;
395     uint8_t buffer[BD_ADDR_LEN];
396     int result = 0;
397     int i;
398     for (i = 0; i < BD_ADDR_LEN; i++) {
399         int single_byte = scan_hex_byte(the_string);
400         if (single_byte < 0) break;
401         the_string += 2;
402         buffer[i] = (uint8_t)single_byte;
403         // don't check separator after last byte
404         if (i == (BD_ADDR_LEN - 1)) {
405             result = 1;
406             break;
407         }
408         // skip supported separators
409         char next_char = *the_string;
410         if ((next_char == ':') || (next_char == '-') || (next_char == ' ')) {
411             the_string++;
412         }
413     }
414 
415     if (result != 0){
416         bd_addr_copy(addr, buffer);
417     }
418 	return result;
419 }
420 
421 uint32_t btstack_atoi(const char * str){
422     const char * the_string = str;
423     uint32_t val = 0;
424     while (true){
425         char chr = *the_string++;
426         if (!chr || (chr < '0') || (chr > '9'))
427             return val;
428         val = (val * 10u) + (uint8_t)(chr - '0');
429     }
430 }
431 
432 int string_len_for_uint32(uint32_t i){
433     if (i <         10) return 1;
434     if (i <        100) return 2;
435     if (i <       1000) return 3;
436     if (i <      10000) return 4;
437     if (i <     100000) return 5;
438     if (i <    1000000) return 6;
439     if (i <   10000000) return 7;
440     if (i <  100000000) return 8;
441     if (i < 1000000000) return 9;
442     return 10;
443 }
444 
445 int count_set_bits_uint32(uint32_t x){
446     uint32_t v = x;
447     v = (v & 0x55555555) + ((v >> 1)  & 0x55555555U);
448     v = (v & 0x33333333) + ((v >> 2)  & 0x33333333U);
449     v = (v & 0x0F0F0F0F) + ((v >> 4)  & 0x0F0F0F0FU);
450     v = (v & 0x00FF00FF) + ((v >> 8)  & 0x00FF00FFU);
451     v = (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFFU);
452     return v;
453 }
454 
455 uint8_t btstack_clz(uint32_t value) {
456 #if defined(__GNUC__) || defined (__clang__)
457     // use gcc/clang intrinsic
458     return (uint8_t) __builtin_clz(value);
459 #elif defined(_MSC_VER)
460     // use MSVC intrinsic
461     DWORD leading_zero = 0;
462     if (_BitScanReverse( &leading_zero, value )){
463 		return (uint8_t)(31 - leading_zero);
464     } else {
465         return 32;
466     }
467 #else
468     // divide-and-conquer implementation for 32-bit integers
469     if (x == 0) return 32;
470     uint8_t r = 0;
471     if ((x & 0xffff0000u) == 0) {
472         x <<= 16;
473         r += 16;
474     }
475     if ((x & 0xff000000u) == 0) {
476         x <<= 8;
477         r += 8;
478     }
479     if ((x & 0xf0000000u) == 0) {
480         x <<= 4;
481         r += 4;
482     }
483     if ((x & 0xc0000000u) == 0) {
484         x <<= 2;
485         r += 2;
486     }
487     if ((x & 0x80000000u) == 0) {
488         x <<= 1;
489         r += 1;
490     }
491     return r;
492 #endif
493 }
494 
495 /*
496  * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
497  */
498 
499 #define CRC8_INIT  0xFF          // Initial FCS value
500 #define CRC8_OK    0xCF          // Good final FCS value
501 
502 static const uint8_t crc8table[256] = {    /* reversed, 8-bit, poly=0x07 */
503     0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
504     0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
505     0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
506     0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
507     0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
508     0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
509     0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
510     0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
511     0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
512     0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
513     0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
514     0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
515     0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
516     0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
517     0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
518     0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
519 };
520 
521 /*-----------------------------------------------------------------------------------*/
522 static uint8_t crc8(uint8_t *data, uint16_t len){
523     uint16_t count;
524     uint8_t crc = CRC8_INIT;
525     for (count = 0; count < len; count++){
526         crc = crc8table[crc ^ data[count]];
527     }
528     return crc;
529 }
530 
531 /*-----------------------------------------------------------------------------------*/
532 uint8_t btstack_crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum){
533     uint8_t crc;
534     crc = crc8(data, len);
535     crc = crc8table[crc ^ check_sum];
536     if (crc == CRC8_OK){
537         return 0;               /* Valid */
538     } else {
539         return 1;               /* Failed */
540     }
541 }
542 
543 /*-----------------------------------------------------------------------------------*/
544 uint8_t btstack_crc8_calc(uint8_t *data, uint16_t len){
545     /* Ones complement */
546     return 0xFFu - crc8(data, len);
547 }
548 
549 uint16_t btstack_next_cid_ignoring_zero(uint16_t current_cid){
550     uint16_t next_cid;
551     if (current_cid == 0xffff) {
552         next_cid = 1;
553     } else {
554         next_cid = current_cid + 1;
555     }
556     return next_cid;
557 }
558 
559 uint16_t btstack_strcpy(char * dst, uint16_t dst_size, const char * src){
560     uint16_t bytes_to_copy = (uint16_t) btstack_min( dst_size - 1, strlen(src));
561     (void) memcpy(dst, src, bytes_to_copy);
562     dst[bytes_to_copy] = 0;
563     return bytes_to_copy + 1;
564 }
565 
566 void btstack_strcat(char * dst, uint16_t dst_size, const char * src){
567     uint16_t src_len = (uint16_t) strlen(src);
568     uint16_t dst_len = (uint16_t) strlen(dst);
569     uint16_t bytes_to_copy = btstack_min( src_len, dst_size - dst_len - 1);
570     (void) memcpy( &dst[dst_len], src, bytes_to_copy);
571     dst[dst_len + bytes_to_copy] = 0;
572 }
573 
574 uint16_t btstack_virtual_memcpy(
575     const uint8_t * field_data, uint16_t field_len, uint16_t field_offset, // position of field in complete data block
576     uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){
577 
578     uint16_t after_buffer = buffer_offset + buffer_size ;
579     // bail before buffer
580     if ((field_offset + field_len) < buffer_offset){
581         return 0;
582     }
583     // bail after buffer
584     if (field_offset >= after_buffer){
585         return 0;
586     }
587     // calc overlap
588     uint16_t bytes_to_copy = field_len;
589 
590     uint16_t skip_at_start = 0;
591     if (field_offset < buffer_offset){
592         skip_at_start = buffer_offset - field_offset;
593         bytes_to_copy -= skip_at_start;
594     }
595 
596     uint16_t skip_at_end = 0;
597     if ((field_offset + field_len) > after_buffer){
598         skip_at_end = (field_offset + field_len) - after_buffer;
599         bytes_to_copy -= skip_at_end;
600     }
601 
602     btstack_assert((skip_at_end + skip_at_start) <= field_len);
603     btstack_assert(bytes_to_copy <= field_len);
604 
605     memcpy(&buffer[(field_offset + skip_at_start) - buffer_offset], &field_data[skip_at_start], bytes_to_copy);
606     return bytes_to_copy;
607 }
608