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