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