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 uint32_t baudrate = uart_config->baudrate; 319 const int flowcontrol = uart_config->flowcontrol; 320 const int parity = uart_config->parity; 321 322 struct termios toptions; 323 int flags = O_RDWR | O_NOCTTY | O_NONBLOCK; 324 int fd = open(device_name, flags); 325 if (fd == -1) { 326 log_error("Unable to open port %s", device_name); 327 return -1; 328 } 329 330 if (tcgetattr(fd, &toptions) < 0) { 331 log_error("Couldn't get term attributes"); 332 return -1; 333 } 334 335 cfmakeraw(&toptions); // make raw 336 337 // 8N1 338 toptions.c_cflag &= ~CSTOPB; 339 toptions.c_cflag |= CS8; 340 341 toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines 342 toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl 343 344 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html 345 toptions.c_cc[VMIN] = 1; 346 toptions.c_cc[VTIME] = 0; 347 348 // no parity 349 btstack_uart_posix_set_parity_option(&toptions, parity); 350 351 // flowcontrol 352 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol); 353 354 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 355 log_error("Couldn't set term attributes"); 356 return -1; 357 } 358 359 // store fd in data source 360 transport_data_source.source.fd = fd; 361 362 // also set baudrate 363 if (btstack_uart_posix_set_baudrate(baudrate) < 0){ 364 return -1; 365 } 366 367 // set up data_source 368 btstack_run_loop_set_data_source_fd(&transport_data_source, fd); 369 btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_uart_posix_process); 370 btstack_run_loop_add_data_source(&transport_data_source); 371 372 // wait a bit - at least cheap FTDI232 clones might send the first byte out incorrectly 373 usleep(100000); 374 375 return 0; 376 } 377 378 static int btstack_uart_posix_close_new(void){ 379 380 // first remove run loop handler 381 btstack_run_loop_remove_data_source(&transport_data_source); 382 383 // then close device 384 close(transport_data_source.source.fd); 385 transport_data_source.source.fd = -1; 386 return 0; 387 } 388 389 static void btstack_uart_posix_set_block_received( void (*block_handler)(void)){ 390 block_received = block_handler; 391 } 392 393 static void btstack_uart_posix_set_block_sent( void (*block_handler)(void)){ 394 block_sent = block_handler; 395 } 396 397 static void btstack_uart_posix_send_block(const uint8_t *data, uint16_t size){ 398 // setup async write 399 btstack_uart_block_write_bytes_data = data; 400 btstack_uart_block_write_bytes_len = size; 401 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE); 402 } 403 404 static void btstack_uart_posix_receive_block(uint8_t *buffer, uint16_t len){ 405 btstack_uart_block_read_bytes_data = buffer; 406 btstack_uart_block_read_bytes_len = len; 407 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ); 408 } 409 410 #ifdef ENABLE_H5 411 412 // SLIP Implementation Start 413 #include "btstack_slip.h" 414 415 // max size of outgoing SLIP chunks 416 #define SLIP_TX_CHUNK_LEN 128 417 418 #define SLIP_RECEIVE_BUFFER_SIZE 128 419 420 // encoded SLIP chunk 421 static uint8_t btstack_uart_slip_outgoing_buffer[SLIP_TX_CHUNK_LEN+1]; 422 423 // block write 424 static int btstack_uart_slip_write_bytes_len; 425 static const uint8_t * btstack_uart_slip_write_bytes_data; 426 static int btstack_uart_slip_write_active; 427 428 // block read 429 static uint8_t btstack_uart_slip_receive_buffer[SLIP_RECEIVE_BUFFER_SIZE]; 430 static uint16_t btstack_uart_slip_receive_pos; 431 static uint16_t btstack_uart_slip_receive_len; 432 static uint8_t btstack_uart_slip_receive_track_start; 433 static uint32_t btstack_uart_slip_receive_start_time; 434 static int btstack_uart_slip_receive_active; 435 436 // callbacks 437 static void (*frame_sent)(void); 438 static void (*frame_received)(uint16_t frame_size); 439 440 static void btstack_uart_slip_posix_block_sent(void); 441 442 static void btstack_uart_slip_posix_process_write(btstack_data_source_t *ds) { 443 444 if (btstack_uart_slip_write_bytes_len == 0) return; 445 446 uint32_t start = btstack_run_loop_get_time_ms(); 447 448 // write up to btstack_uart_slip_write_bytes_len to fd 449 int bytes_written = (int) write(ds->source.fd, btstack_uart_slip_write_bytes_data, btstack_uart_slip_write_bytes_len); 450 if (bytes_written < 0) { 451 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 452 return; 453 } 454 455 uint32_t end = btstack_run_loop_get_time_ms(); 456 if (end - start > 10){ 457 log_info("write took %u ms", end - start); 458 } 459 460 btstack_uart_slip_write_bytes_data += bytes_written; 461 btstack_uart_slip_write_bytes_len -= bytes_written; 462 463 if (btstack_uart_slip_write_bytes_len){ 464 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 465 return; 466 } 467 468 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 469 470 // done with TX chunk 471 btstack_uart_slip_posix_block_sent(); 472 } 473 474 // @returns frame size if complete frame decoded and delivered 475 static uint16_t btstack_uart_slip_posix_process_buffer(void){ 476 log_debug("process buffer: pos %u, len %u", btstack_uart_slip_receive_pos, btstack_uart_slip_receive_len); 477 478 uint16_t frame_size = 0; 479 while (btstack_uart_slip_receive_pos < btstack_uart_slip_receive_len && frame_size == 0){ 480 btstack_slip_decoder_process(btstack_uart_slip_receive_buffer[btstack_uart_slip_receive_pos++]); 481 frame_size = btstack_slip_decoder_frame_size(); 482 } 483 484 // reset buffer if fully processed 485 if (btstack_uart_slip_receive_pos == btstack_uart_slip_receive_len ){ 486 btstack_uart_slip_receive_len = 0; 487 btstack_uart_slip_receive_pos = 0; 488 } 489 490 // deliver frame if frame complete 491 if (frame_size) { 492 493 // receive done 494 btstack_uart_slip_receive_active = 0; 495 496 // only print if read was involved 497 if (btstack_uart_slip_receive_track_start == 0){ 498 log_info("frame receive time %u ms", btstack_run_loop_get_time_ms() - btstack_uart_slip_receive_start_time); 499 btstack_uart_slip_receive_start_time = 0; 500 } 501 502 (*frame_received)(frame_size); 503 } 504 505 return frame_size; 506 } 507 508 static void btstack_uart_slip_posix_process_read(btstack_data_source_t *ds) { 509 510 uint32_t start = btstack_run_loop_get_time_ms(); 511 512 if (btstack_uart_slip_receive_track_start){ 513 btstack_uart_slip_receive_track_start = 0; 514 btstack_uart_slip_receive_start_time = start; 515 } 516 517 // read up to bytes_to_read data in 518 ssize_t bytes_read = read(ds->source.fd, btstack_uart_slip_receive_buffer, SLIP_RECEIVE_BUFFER_SIZE); 519 520 log_debug("requested %u bytes, got %d", SLIP_RECEIVE_BUFFER_SIZE, (int) bytes_read); 521 uint32_t end = btstack_run_loop_get_time_ms(); 522 if (end - start > 10){ 523 log_info("read took %u ms", end - start); 524 } 525 if (bytes_read < 0) return; 526 527 btstack_uart_slip_receive_pos = 0; 528 btstack_uart_slip_receive_len = (uint16_t ) bytes_read; 529 530 btstack_uart_slip_posix_process_buffer(); 531 } 532 533 // ----------------------------- 534 // SLIP ENCODING 535 536 static void btstack_uart_slip_posix_encode_chunk_and_send(void){ 537 uint16_t pos = 0; 538 while (btstack_slip_encoder_has_data() & (pos < SLIP_TX_CHUNK_LEN)) { 539 btstack_uart_slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte(); 540 } 541 542 // setup async write and start sending 543 log_debug("slip: send %d bytes", pos); 544 btstack_uart_slip_write_bytes_data = btstack_uart_slip_outgoing_buffer; 545 btstack_uart_slip_write_bytes_len = pos; 546 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE); 547 } 548 549 static void btstack_uart_slip_posix_block_sent(void){ 550 // check if more data to send 551 if (btstack_slip_encoder_has_data()){ 552 btstack_uart_slip_posix_encode_chunk_and_send(); 553 return; 554 } 555 556 // write done 557 btstack_uart_slip_write_active = 0; 558 559 // notify done 560 if (frame_sent){ 561 frame_sent(); 562 } 563 } 564 565 static void btstack_uart_slip_posix_send_frame(const uint8_t * frame, uint16_t frame_size){ 566 567 // write started 568 btstack_uart_slip_write_active = 1; 569 570 // Prepare encoding of Header + Packet (+ DIC) 571 btstack_slip_encoder_start(frame, frame_size); 572 573 // Fill rest of chunk from packet and send 574 btstack_uart_slip_posix_encode_chunk_and_send(); 575 } 576 577 // SLIP ENCODING 578 // ----------------------------- 579 580 static void btstack_uart_slip_posix_receive_frame(uint8_t *buffer, uint16_t len){ 581 582 // receive started 583 btstack_uart_slip_receive_active = 1; 584 585 log_debug("receive block, size %u", len); 586 btstack_uart_slip_receive_track_start = 1; 587 588 // setup SLIP decoder 589 btstack_slip_decoder_init(buffer, len); 590 591 // process bytes received in earlier read. might deliver packet, which in turn will call us again. 592 // just make sure to exit right away 593 if (btstack_uart_slip_receive_len){ 594 int frame_found = btstack_uart_slip_posix_process_buffer(); 595 if (frame_found) return; 596 } 597 598 // no frame delivered, enable posix read 599 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ); 600 } 601 602 603 604 static void btstack_uart_slip_posix_set_frame_received( void (*block_handler)(uint16_t frame_size)){ 605 frame_received = block_handler; 606 } 607 608 static void btstack_uart_slip_posix_set_frame_sent( void (*block_handler)(void)){ 609 frame_sent = block_handler; 610 } 611 612 // SLIP Implementation End 613 #endif 614 615 // dispatch into block or SLIP code 616 static void hci_uart_posix_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) { 617 if (ds->source.fd < 0) return; 618 switch (callback_type){ 619 case DATA_SOURCE_CALLBACK_READ: 620 #ifdef ENABLE_H5 621 if (btstack_uart_slip_receive_active){ 622 btstack_uart_slip_posix_process_read(ds); 623 } else 624 #endif 625 { 626 btstack_uart_block_posix_process_read(ds); 627 } 628 break; 629 case DATA_SOURCE_CALLBACK_WRITE: 630 #ifdef ENABLE_H5 631 if (btstack_uart_slip_write_active){ 632 btstack_uart_slip_posix_process_write(ds); 633 } else 634 #endif 635 { 636 btstack_uart_block_posix_process_write(ds); 637 } 638 break; 639 default: 640 break; 641 } 642 } 643 644 static const btstack_uart_t btstack_uart_posix = { 645 /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_posix_init, 646 /* int (*open)(void); */ &btstack_uart_posix_open, 647 /* int (*close)(void); */ &btstack_uart_posix_close_new, 648 /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_posix_set_block_received, 649 /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_posix_set_block_sent, 650 /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_posix_set_baudrate, 651 /* int (*set_parity)(int parity); */ &btstack_uart_posix_set_parity, 652 /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_posix_set_flowcontrol, 653 /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_posix_receive_block, 654 /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_posix_send_block, 655 /* int (*get_supported_sleep_modes); */ NULL, 656 /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL, 657 /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL, 658 659 #ifdef ENABLE_H5 660 /* void (*set_frame_received)(void (*handler)(uint16_t frame_size); */ &btstack_uart_slip_posix_set_frame_received, 661 /* void (*set_fraae_sent)(void (*handler)(void)); */ &btstack_uart_slip_posix_set_frame_sent, 662 /* void (*receive_frame)(uint8_t *buffer, uint16_t len); */ &btstack_uart_slip_posix_receive_frame, 663 /* void (*send_frame)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_slip_posix_send_frame, 664 #else 665 NULL, NULL, NULL, NULL, 666 #endif 667 }; 668 669 const btstack_uart_t * btstack_uart_posix_instance(void){ 670 return &btstack_uart_posix; 671 } 672