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