1 /* 2 * Copyright (C) 2016 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 MATTHIAS 24 * RINGWALD 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_uart_posix.c" 39 40 /* 41 * btstack_uart_posix.c 42 * 43 * Common code to access serial port via asynchronous block read/write commands 44 * 45 */ 46 47 #include "btstack_uart.h" 48 #include "btstack_run_loop.h" 49 #include "btstack_debug.h" 50 51 #include <termios.h> /* POSIX terminal control definitions */ 52 #include <fcntl.h> /* File control definitions */ 53 #include <unistd.h> /* UNIX standard function definitions */ 54 #include <string.h> 55 #include <errno.h> 56 #ifdef __APPLE__ 57 #include <sys/ioctl.h> 58 #include <IOKit/serial/ioss.h> 59 #endif 60 61 // uart config 62 static const btstack_uart_config_t * uart_config; 63 64 // data source for integration with BTstack Runloop 65 static btstack_data_source_t transport_data_source; 66 67 // block write 68 static int btstack_uart_block_write_bytes_len; 69 static const uint8_t * btstack_uart_block_write_bytes_data; 70 71 // block read 72 static uint16_t btstack_uart_block_read_bytes_len; 73 static uint8_t * btstack_uart_block_read_bytes_data; 74 75 // callbacks 76 static void (*block_sent)(void); 77 static void (*block_received)(void); 78 79 80 static int btstack_uart_posix_init(const btstack_uart_config_t * config){ 81 uart_config = config; 82 return 0; 83 } 84 85 static void hci_uart_posix_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type); 86 87 static void btstack_uart_block_posix_process_write(btstack_data_source_t *ds) { 88 89 if (btstack_uart_block_write_bytes_len == 0) return; 90 91 uint32_t start = btstack_run_loop_get_time_ms(); 92 93 // write up to write_bytes_len to fd 94 int bytes_written = (int) write(ds->source.fd, btstack_uart_block_write_bytes_data, btstack_uart_block_write_bytes_len); 95 uint32_t end = btstack_run_loop_get_time_ms(); 96 if (end - start > 10){ 97 log_info("write took %u ms", end - start); 98 } 99 if (bytes_written == 0){ 100 log_error("wrote zero bytes\n"); 101 return; 102 } 103 if (bytes_written < 0) { 104 log_error("write returned error\n"); 105 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 106 return; 107 } 108 109 btstack_uart_block_write_bytes_data += bytes_written; 110 btstack_uart_block_write_bytes_len -= bytes_written; 111 112 if (btstack_uart_block_write_bytes_len){ 113 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 114 return; 115 } 116 117 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 118 119 // notify done 120 if (block_sent){ 121 block_sent(); 122 } 123 } 124 125 static void btstack_uart_block_posix_process_read(btstack_data_source_t *ds) { 126 127 if (btstack_uart_block_read_bytes_len == 0) { 128 log_info("called but no read pending"); 129 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ); 130 } 131 132 uint32_t start = btstack_run_loop_get_time_ms(); 133 134 // read up to bytes_to_read data in 135 ssize_t bytes_read = read(ds->source.fd, btstack_uart_block_read_bytes_data, btstack_uart_block_read_bytes_len); 136 // log_info("read need %u bytes, got %d", btstack_uart_block_read_bytes_len, (int) bytes_read); 137 uint32_t end = btstack_run_loop_get_time_ms(); 138 if (end - start > 10){ 139 log_info("read took %u ms", end - start); 140 } 141 if (bytes_read == 0){ 142 log_error("read zero bytes\n"); 143 return; 144 } 145 if (bytes_read < 0) { 146 log_error("read returned error\n"); 147 return; 148 } 149 150 btstack_uart_block_read_bytes_len -= bytes_read; 151 btstack_uart_block_read_bytes_data += bytes_read; 152 if (btstack_uart_block_read_bytes_len > 0) return; 153 154 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ); 155 156 if (block_received){ 157 block_received(); 158 } 159 } 160 161 static int btstack_uart_posix_set_baudrate(uint32_t baudrate){ 162 163 int fd = transport_data_source.source.fd; 164 165 log_info("h4_set_baudrate %u", baudrate); 166 167 struct termios toptions; 168 169 if (tcgetattr(fd, &toptions) < 0) { 170 log_error("btstack_uart_posix_set_baudrate: Couldn't get term attributes"); 171 return -1; 172 } 173 174 #ifndef __APPLE__ 175 176 speed_t brate = baudrate; // let you override switch below if needed 177 switch(baudrate) { 178 case 9600: brate=B9600; break; 179 case 19200: brate=B19200; break; 180 case 38400: brate=B38400; break; 181 case 57600: brate=B57600; break; 182 case 115200: brate=B115200; break; 183 #ifdef B230400 184 case 230400: brate=B230400; break; 185 #endif 186 #ifdef B460800 187 case 460800: brate=B460800; break; 188 #endif 189 #ifdef B500000 190 case 500000: brate=B500000; break; 191 #endif 192 #ifdef B576000 193 case 576000: brate=B576000; break; 194 #endif 195 #ifdef B921600 196 case 921600: brate=B921600; break; 197 #endif 198 #ifdef B1000000 199 case 1000000: brate=B1000000; break; 200 #endif 201 #ifdef B1152000 202 case 1152000: brate=B1152000; break; 203 #endif 204 #ifdef B1500000 205 case 1500000: brate=B1500000; break; 206 #endif 207 #ifdef B2000000 208 case 2000000: brate=B2000000; break; 209 #endif 210 #ifdef B2500000 211 case 2500000: brate=B2500000; break; 212 #endif 213 #ifdef B3000000 214 case 3000000: brate=B3000000; break; 215 #endif 216 #ifdef B3500000 217 case 3500000: brate=B3500000; break; 218 #endif 219 #ifdef B400000 220 case 4000000: brate=B4000000; break; 221 #endif 222 default: 223 log_error("can't set baudrate %dn", baudrate ); 224 return -1; 225 } 226 cfsetospeed(&toptions, brate); 227 cfsetispeed(&toptions, brate); 228 #endif 229 230 // also set options for __APPLE__ to enforce write drain 231 // Mac OS Mojave: tcsdrain did not work as expected 232 233 if( tcsetattr(fd, TCSADRAIN, &toptions) < 0) { 234 log_error("Couldn't set term attributes"); 235 return -1; 236 } 237 238 #ifdef __APPLE__ 239 // From https://developer.apple.com/library/content/samplecode/SerialPortSample/Listings/SerialPortSample_SerialPortSample_c.html 240 241 // The IOSSIOSPEED ioctl can be used to set arbitrary baud rates 242 // other than those specified by POSIX. The driver for the underlying serial hardware 243 // ultimately determines which baud rates can be used. This ioctl sets both the input 244 // and output speed. 245 246 speed_t speed = baudrate; 247 if (ioctl(fd, IOSSIOSPEED, &speed) == -1) { 248 log_error("btstack_uart_posix_set_baudrate: error calling ioctl(..., IOSSIOSPEED, %u) - %s(%d).\n", baudrate, strerror(errno), errno); 249 return -1; 250 } 251 #endif 252 253 return 0; 254 } 255 256 static void btstack_uart_posix_set_parity_option(struct termios * toptions, int parity){ 257 switch (parity){ 258 case BTSTACK_UART_PARITY_OFF: 259 toptions->c_cflag &= ~PARENB; 260 toptions->c_cflag &= ~PARODD; 261 break; 262 case BTSTACK_UART_PARITY_EVEN: 263 toptions->c_cflag |= PARENB; 264 toptions->c_cflag &= ~PARODD; 265 break; 266 case BTSTACK_UART_PARITY_ODD: 267 toptions->c_cflag |= PARENB; 268 toptions->c_cflag |= PARODD; 269 default: 270 break; 271 } 272 } 273 274 static void btstack_uart_posix_set_flowcontrol_option(struct termios * toptions, int flowcontrol){ 275 if (flowcontrol) { 276 // with flow control 277 toptions->c_cflag |= CRTSCTS; 278 } else { 279 // no flow control 280 toptions->c_cflag &= ~CRTSCTS; 281 } 282 } 283 284 static int btstack_uart_posix_set_parity(int parity){ 285 int fd = transport_data_source.source.fd; 286 struct termios toptions; 287 if (tcgetattr(fd, &toptions) < 0) { 288 log_error("Couldn't get term attributes"); 289 return -1; 290 } 291 btstack_uart_posix_set_parity_option(&toptions, parity); 292 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 293 log_error("Couldn't set term attributes"); 294 return -1; 295 } 296 return 0; 297 } 298 299 300 static int btstack_uart_posix_set_flowcontrol(int flowcontrol){ 301 int fd = transport_data_source.source.fd; 302 struct termios toptions; 303 if (tcgetattr(fd, &toptions) < 0) { 304 log_error("Couldn't get term attributes"); 305 return -1; 306 } 307 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol); 308 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 309 log_error("Couldn't set term attributes"); 310 return -1; 311 } 312 return 0; 313 } 314 315 static int btstack_uart_posix_open(void){ 316 317 const char * device_name = uart_config->device_name; 318 const int flowcontrol = uart_config->flowcontrol; 319 const uint32_t baudrate = uart_config->baudrate; 320 321 struct termios toptions; 322 int flags = O_RDWR | O_NOCTTY | O_NONBLOCK; 323 int fd = open(device_name, flags); 324 if (fd == -1) { 325 log_error("Unable to open port %s", device_name); 326 return -1; 327 } 328 329 if (tcgetattr(fd, &toptions) < 0) { 330 log_error("Couldn't get term attributes"); 331 return -1; 332 } 333 334 cfmakeraw(&toptions); // make raw 335 336 // 8N1 337 toptions.c_cflag &= ~CSTOPB; 338 toptions.c_cflag |= CS8; 339 340 toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines 341 toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl 342 343 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html 344 toptions.c_cc[VMIN] = 1; 345 toptions.c_cc[VTIME] = 0; 346 347 // no parity 348 btstack_uart_posix_set_parity_option(&toptions, 0); 349 350 // flowcontrol 351 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol); 352 353 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 354 log_error("Couldn't set term attributes"); 355 return -1; 356 } 357 358 // store fd in data source 359 transport_data_source.source.fd = fd; 360 361 // also set baudrate 362 if (btstack_uart_posix_set_baudrate(baudrate) < 0){ 363 return -1; 364 } 365 366 // set up data_source 367 btstack_run_loop_set_data_source_fd(&transport_data_source, fd); 368 btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_uart_posix_process); 369 btstack_run_loop_add_data_source(&transport_data_source); 370 371 // wait a bit - at least cheap FTDI232 clones might send the first byte out incorrectly 372 usleep(100000); 373 374 return 0; 375 } 376 377 static int btstack_uart_posix_close_new(void){ 378 379 // first remove run loop handler 380 btstack_run_loop_remove_data_source(&transport_data_source); 381 382 // then close device 383 close(transport_data_source.source.fd); 384 transport_data_source.source.fd = -1; 385 return 0; 386 } 387 388 static void btstack_uart_posix_set_block_received( void (*block_handler)(void)){ 389 block_received = block_handler; 390 } 391 392 static void btstack_uart_posix_set_block_sent( void (*block_handler)(void)){ 393 block_sent = block_handler; 394 } 395 396 static void btstack_uart_posix_send_block(const uint8_t *data, uint16_t size){ 397 // setup async write 398 btstack_uart_block_write_bytes_data = data; 399 btstack_uart_block_write_bytes_len = size; 400 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE); 401 } 402 403 static void btstack_uart_posix_receive_block(uint8_t *buffer, uint16_t len){ 404 btstack_uart_block_read_bytes_data = buffer; 405 btstack_uart_block_read_bytes_len = len; 406 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ); 407 } 408 409 #ifdef ENABLE_H5 410 411 // SLIP Implementation Start 412 #include "btstack_slip.h" 413 414 // max size of outgoing SLIP chunks 415 #define SLIP_TX_CHUNK_LEN 128 416 417 #define SLIP_RECEIVE_BUFFER_SIZE 128 418 419 // encoded SLIP chunk 420 static uint8_t btstack_uart_slip_outgoing_buffer[SLIP_TX_CHUNK_LEN+1]; 421 422 // block write 423 static int btstack_uart_slip_write_bytes_len; 424 static const uint8_t * btstack_uart_slip_write_bytes_data; 425 static int btstack_uart_slip_write_active; 426 427 // block read 428 static uint8_t btstack_uart_slip_receive_buffer[SLIP_RECEIVE_BUFFER_SIZE]; 429 static uint16_t btstack_uart_slip_receive_pos; 430 static uint16_t btstack_uart_slip_receive_len; 431 static uint8_t btstack_uart_slip_receive_track_start; 432 static uint32_t btstack_uart_slip_receive_start_time; 433 static int btstack_uart_slip_receive_active; 434 435 // callbacks 436 static void (*frame_sent)(void); 437 static void (*frame_received)(uint16_t frame_size); 438 439 static void btstack_uart_slip_posix_block_sent(void); 440 441 static void btstack_uart_slip_posix_process_write(btstack_data_source_t *ds) { 442 443 if (btstack_uart_slip_write_bytes_len == 0) return; 444 445 uint32_t start = btstack_run_loop_get_time_ms(); 446 447 // write up to btstack_uart_slip_write_bytes_len to fd 448 int bytes_written = (int) write(ds->source.fd, btstack_uart_slip_write_bytes_data, btstack_uart_slip_write_bytes_len); 449 if (bytes_written < 0) { 450 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 451 return; 452 } 453 454 uint32_t end = btstack_run_loop_get_time_ms(); 455 if (end - start > 10){ 456 log_info("write took %u ms", end - start); 457 } 458 459 btstack_uart_slip_write_bytes_data += bytes_written; 460 btstack_uart_slip_write_bytes_len -= bytes_written; 461 462 if (btstack_uart_slip_write_bytes_len){ 463 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 464 return; 465 } 466 467 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 468 469 // done with TX chunk 470 btstack_uart_slip_posix_block_sent(); 471 } 472 473 // @returns frame size if complete frame decoded and delivered 474 static uint16_t btstack_uart_slip_posix_process_buffer(void){ 475 log_debug("process buffer: pos %u, len %u", btstack_uart_slip_receive_pos, btstack_uart_slip_receive_len); 476 477 uint16_t frame_size = 0; 478 while (btstack_uart_slip_receive_pos < btstack_uart_slip_receive_len && frame_size == 0){ 479 btstack_slip_decoder_process(btstack_uart_slip_receive_buffer[btstack_uart_slip_receive_pos++]); 480 frame_size = btstack_slip_decoder_frame_size(); 481 } 482 483 // reset buffer if fully processed 484 if (btstack_uart_slip_receive_pos == btstack_uart_slip_receive_len ){ 485 btstack_uart_slip_receive_len = 0; 486 btstack_uart_slip_receive_pos = 0; 487 } 488 489 // deliver frame if frame complete 490 if (frame_size) { 491 492 // receive done 493 btstack_uart_slip_receive_active = 0; 494 495 // only print if read was involved 496 if (btstack_uart_slip_receive_track_start == 0){ 497 log_info("frame receive time %u ms", btstack_run_loop_get_time_ms() - btstack_uart_slip_receive_start_time); 498 btstack_uart_slip_receive_start_time = 0; 499 } 500 501 (*frame_received)(frame_size); 502 } 503 504 return frame_size; 505 } 506 507 static void btstack_uart_slip_posix_process_read(btstack_data_source_t *ds) { 508 509 uint32_t start = btstack_run_loop_get_time_ms(); 510 511 if (btstack_uart_slip_receive_track_start){ 512 btstack_uart_slip_receive_track_start = 0; 513 btstack_uart_slip_receive_start_time = start; 514 } 515 516 // read up to bytes_to_read data in 517 ssize_t bytes_read = read(ds->source.fd, btstack_uart_slip_receive_buffer, SLIP_RECEIVE_BUFFER_SIZE); 518 519 log_debug("requested %u bytes, got %d", SLIP_RECEIVE_BUFFER_SIZE, (int) bytes_read); 520 uint32_t end = btstack_run_loop_get_time_ms(); 521 if (end - start > 10){ 522 log_info("read took %u ms", end - start); 523 } 524 if (bytes_read < 0) return; 525 526 btstack_uart_slip_receive_pos = 0; 527 btstack_uart_slip_receive_len = (uint16_t ) bytes_read; 528 529 btstack_uart_slip_posix_process_buffer(); 530 } 531 532 // ----------------------------- 533 // SLIP ENCODING 534 535 static void btstack_uart_slip_posix_encode_chunk_and_send(void){ 536 uint16_t pos = 0; 537 while (btstack_slip_encoder_has_data() & (pos < SLIP_TX_CHUNK_LEN)) { 538 btstack_uart_slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte(); 539 } 540 541 // setup async write and start sending 542 log_debug("slip: send %d bytes", pos); 543 btstack_uart_slip_write_bytes_data = btstack_uart_slip_outgoing_buffer; 544 btstack_uart_slip_write_bytes_len = pos; 545 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE); 546 } 547 548 static void btstack_uart_slip_posix_block_sent(void){ 549 // check if more data to send 550 if (btstack_slip_encoder_has_data()){ 551 btstack_uart_slip_posix_encode_chunk_and_send(); 552 return; 553 } 554 555 // write done 556 btstack_uart_slip_write_active = 0; 557 558 // notify done 559 if (frame_sent){ 560 frame_sent(); 561 } 562 } 563 564 static void btstack_uart_slip_posix_send_frame(const uint8_t * frame, uint16_t frame_size){ 565 566 // write started 567 btstack_uart_slip_write_active = 1; 568 569 // Prepare encoding of Header + Packet (+ DIC) 570 btstack_slip_encoder_start(frame, frame_size); 571 572 // Fill rest of chunk from packet and send 573 btstack_uart_slip_posix_encode_chunk_and_send(); 574 } 575 576 // SLIP ENCODING 577 // ----------------------------- 578 579 static void btstack_uart_slip_posix_receive_frame(uint8_t *buffer, uint16_t len){ 580 581 // receive started 582 btstack_uart_slip_receive_active = 1; 583 584 log_debug("receive block, size %u", len); 585 btstack_uart_slip_receive_track_start = 1; 586 587 // setup SLIP decoder 588 btstack_slip_decoder_init(buffer, len); 589 590 // process bytes received in earlier read. might deliver packet, which in turn will call us again. 591 // just make sure to exit right away 592 if (btstack_uart_slip_receive_len){ 593 int frame_found = btstack_uart_slip_posix_process_buffer(); 594 if (frame_found) return; 595 } 596 597 // no frame delivered, enable posix read 598 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ); 599 } 600 601 602 603 static void btstack_uart_slip_posix_set_frame_received( void (*block_handler)(uint16_t frame_size)){ 604 frame_received = block_handler; 605 } 606 607 static void btstack_uart_slip_posix_set_frame_sent( void (*block_handler)(void)){ 608 frame_sent = block_handler; 609 } 610 611 // SLIP Implementation End 612 #endif 613 614 // dispatch into block or SLIP code 615 static void hci_uart_posix_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) { 616 if (ds->source.fd < 0) return; 617 switch (callback_type){ 618 case DATA_SOURCE_CALLBACK_READ: 619 #ifdef ENABLE_H5 620 if (btstack_uart_slip_receive_active){ 621 btstack_uart_slip_posix_process_read(ds); 622 } else 623 #endif 624 { 625 btstack_uart_block_posix_process_read(ds); 626 } 627 break; 628 case DATA_SOURCE_CALLBACK_WRITE: 629 #ifdef ENABLE_H5 630 if (btstack_uart_slip_write_active){ 631 btstack_uart_slip_posix_process_write(ds); 632 } else 633 #endif 634 { 635 btstack_uart_block_posix_process_write(ds); 636 } 637 break; 638 default: 639 break; 640 } 641 } 642 643 static const btstack_uart_t btstack_uart_posix = { 644 /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_posix_init, 645 /* int (*open)(void); */ &btstack_uart_posix_open, 646 /* int (*close)(void); */ &btstack_uart_posix_close_new, 647 /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_posix_set_block_received, 648 /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_posix_set_block_sent, 649 /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_posix_set_baudrate, 650 /* int (*set_parity)(int parity); */ &btstack_uart_posix_set_parity, 651 /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_posix_set_flowcontrol, 652 /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_posix_receive_block, 653 /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_posix_send_block, 654 /* int (*get_supported_sleep_modes); */ NULL, 655 /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL, 656 /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL, 657 658 #ifdef ENABLE_H5 659 /* void (*set_frame_received)(void (*handler)(uint16_t frame_size); */ &btstack_uart_slip_posix_set_frame_received, 660 /* void (*set_fraae_sent)(void (*handler)(void)); */ &btstack_uart_slip_posix_set_frame_sent, 661 /* void (*receive_frame)(uint8_t *buffer, uint16_t len); */ &btstack_uart_slip_posix_receive_frame, 662 /* void (*send_frame)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_slip_posix_send_frame, 663 #else 664 NULL, NULL, NULL, NULL, 665 #endif 666 }; 667 668 const btstack_uart_t * btstack_uart_posix_instance(void){ 669 return &btstack_uart_posix; 670 } 671