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_block_posix.c 42 * 43 * Common code to access serial port via asynchronous block read/write commands 44 * 45 */ 46 47 #include "btstack_uart_block.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 write_bytes_len; 69 static const uint8_t * write_bytes_data; 70 71 // block read 72 static uint16_t read_bytes_len; 73 static uint8_t * 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 btstack_uart_posix_process_write(btstack_data_source_t *ds) { 86 87 if (write_bytes_len == 0) return; 88 89 uint32_t start = btstack_run_loop_get_time_ms(); 90 91 // write up to write_bytes_len to fd 92 int bytes_written = (int) write(ds->source.fd, write_bytes_data, write_bytes_len); 93 if (bytes_written < 0) { 94 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 95 return; 96 } 97 98 uint32_t end = btstack_run_loop_get_time_ms(); 99 if (end - start > 10){ 100 log_info("h4_process: write took %u ms", end - start); 101 } 102 103 write_bytes_data += bytes_written; 104 write_bytes_len -= bytes_written; 105 106 if (write_bytes_len){ 107 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 108 return; 109 } 110 111 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE); 112 113 // notify done 114 if (block_sent){ 115 block_sent(); 116 } 117 } 118 119 static void btstack_uart_posix_process_read(btstack_data_source_t *ds) { 120 121 if (read_bytes_len == 0) { 122 log_info("btstack_uart_posix_process_read but no read requested"); 123 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ); 124 } 125 126 uint32_t start = btstack_run_loop_get_time_ms(); 127 128 // read up to bytes_to_read data in 129 ssize_t bytes_read = read(ds->source.fd, read_bytes_data, read_bytes_len); 130 // log_info("btstack_uart_posix_process_read need %u bytes, got %d", read_bytes_len, (int) bytes_read); 131 uint32_t end = btstack_run_loop_get_time_ms(); 132 if (end - start > 10){ 133 log_info("h4_process: read took %u ms", end - start); 134 } 135 if (bytes_read < 0) return; 136 137 read_bytes_len -= bytes_read; 138 read_bytes_data += bytes_read; 139 if (read_bytes_len > 0) return; 140 141 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ); 142 143 if (block_received){ 144 block_received(); 145 } 146 } 147 148 static void hci_transport_h5_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) { 149 if (ds->source.fd < 0) return; 150 switch (callback_type){ 151 case DATA_SOURCE_CALLBACK_READ: 152 btstack_uart_posix_process_read(ds); 153 break; 154 case DATA_SOURCE_CALLBACK_WRITE: 155 btstack_uart_posix_process_write(ds); 156 break; 157 default: 158 break; 159 } 160 } 161 162 static int btstack_uart_posix_set_baudrate(uint32_t baudrate){ 163 UNUSED(baudrate); 164 #if 0 165 int fd = transport_data_source.source.fd; 166 167 log_info("h4_set_baudrate %u", baudrate); 168 169 #ifdef __APPLE__ 170 171 // From https://developer.apple.com/library/content/samplecode/SerialPortSample/Listings/SerialPortSample_SerialPortSample_c.html 172 173 // The IOSSIOSPEED ioctl can be used to set arbitrary baud rates 174 // other than those specified by POSIX. The driver for the underlying serial hardware 175 // ultimately determines which baud rates can be used. This ioctl sets both the input 176 // and output speed. 177 178 speed_t speed = baudrate; 179 if (ioctl(fd, IOSSIOSPEED, &speed) == -1) { 180 log_error("btstack_uart_posix_set_baudrate: error calling ioctl(..., IOSSIOSPEED, %u) - %s(%d).\n", baudrate, strerror(errno), errno); 181 return -1; 182 } 183 184 #else 185 struct termios toptions; 186 187 if (tcgetattr(fd, &toptions) < 0) { 188 log_error("btstack_uart_posix_set_baudrate: Couldn't get term attributes"); 189 return -1; 190 } 191 192 speed_t brate = baudrate; // let you override switch below if needed 193 switch(baudrate) { 194 case 57600: brate=B57600; break; 195 case 115200: brate=B115200; break; 196 #ifdef B230400 197 case 230400: brate=B230400; break; 198 #endif 199 #ifdef B460800 200 case 460800: brate=B460800; break; 201 #endif 202 #ifdef B921600 203 case 921600: brate=B921600; break; 204 #endif 205 206 // Hacks to switch to 2/3 mbps on FTDI FT232 chipsets 207 // requires special config in Info.plist or Registry 208 case 2000000: 209 #if defined(HAVE_POSIX_B300_MAPPED_TO_2000000) 210 log_info("hci_transport_posix: using B300 for 2 mbps"); 211 brate=B300; 212 #elif defined(HAVE_POSIX_B1200_MAPPED_TO_2000000) 213 log_info("hci_transport_posix: using B1200 for 2 mbps"); 214 brate=B1200; 215 #endif 216 break; 217 case 3000000: 218 #if defined(HAVE_POSIX_B600_MAPPED_TO_3000000) 219 log_info("hci_transport_posix: using B600 for 3 mbps"); 220 brate=B600; 221 #elif defined(HAVE_POSIX_B2400_MAPPED_TO_3000000) 222 log_info("hci_transport_posix: using B2400 for 3 mbps"); 223 brate=B2400; 224 #endif 225 break; 226 default: 227 break; 228 } 229 cfsetospeed(&toptions, brate); 230 cfsetispeed(&toptions, brate); 231 232 if( tcsetattr(fd, TCSANOW, &toptions) < 0) { 233 log_error("btstack_uart_posix_set_baudrate: Couldn't set term attributes"); 234 return -1; 235 } 236 #endif 237 #endif 238 return 0; 239 } 240 241 static void btstack_uart_posix_set_parity_option(struct termios * toptions, int parity){ 242 if (parity){ 243 // enable even parity 244 toptions->c_cflag |= PARENB; 245 } else { 246 // disable even parity 247 toptions->c_cflag &= ~PARENB; 248 } 249 } 250 251 static void btstack_uart_posix_set_flowcontrol_option(struct termios * toptions, int flowcontrol){ 252 if (flowcontrol) { 253 // with flow control 254 toptions->c_cflag |= CRTSCTS; 255 } else { 256 // no flow control 257 toptions->c_cflag &= ~CRTSCTS; 258 } 259 } 260 261 static int btstack_uart_posix_set_parity(int parity){ 262 int fd = transport_data_source.source.fd; 263 struct termios toptions; 264 if (tcgetattr(fd, &toptions) < 0) { 265 log_error("btstack_uart_posix_set_parity: Couldn't get term attributes"); 266 return -1; 267 } 268 btstack_uart_posix_set_parity_option(&toptions, parity); 269 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 270 log_error("posix_set_parity: Couldn't set term attributes"); 271 return -1; 272 } 273 return 0; 274 } 275 276 277 static int btstack_uart_posix_set_flowcontrol(int flowcontrol){ 278 int fd = transport_data_source.source.fd; 279 struct termios toptions; 280 if (tcgetattr(fd, &toptions) < 0) { 281 log_error("btstack_uart_posix_set_parity: Couldn't get term attributes"); 282 return -1; 283 } 284 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol); 285 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 286 log_error("posix_set_flowcontrol: Couldn't set term attributes"); 287 return -1; 288 } 289 return 0; 290 } 291 292 static int btstack_uart_posix_open(void){ 293 294 const char * device_name = uart_config->device_name; 295 const int flowcontrol = uart_config->flowcontrol; 296 const uint32_t baudrate = uart_config->baudrate; 297 298 struct termios toptions; 299 int flags = O_RDWR | O_NOCTTY | O_NONBLOCK; 300 int fd = open(device_name, flags); 301 if (fd == -1) { 302 log_error("posix_open: Unable to open port %s", device_name); 303 return -1; 304 } 305 306 if (tcgetattr(fd, &toptions) < 0) { 307 log_error("posix_open: Couldn't get term attributes"); 308 return -1; 309 } 310 311 cfmakeraw(&toptions); // make raw 312 313 // 8N1 314 toptions.c_cflag &= ~CSTOPB; 315 toptions.c_cflag |= CS8; 316 317 toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines 318 toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl 319 320 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html 321 toptions.c_cc[VMIN] = 1; 322 toptions.c_cc[VTIME] = 0; 323 324 // no parity 325 btstack_uart_posix_set_parity_option(&toptions, 0); 326 327 // flowcontrol 328 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol); 329 330 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 331 log_error("posix_open: Couldn't set term attributes"); 332 return -1; 333 } 334 335 // store fd in data source 336 transport_data_source.source.fd = fd; 337 338 // also set baudrate 339 if (btstack_uart_posix_set_baudrate(baudrate) < 0){ 340 return -1; 341 } 342 343 // set up data_source 344 btstack_run_loop_set_data_source_fd(&transport_data_source, fd); 345 btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_transport_h5_process); 346 btstack_run_loop_add_data_source(&transport_data_source); 347 348 // wait a bit - at least cheap FTDI232 clones might send the first byte out incorrectly 349 usleep(100000); 350 351 return 0; 352 } 353 354 static int btstack_uart_posix_close_new(void){ 355 356 // first remove run loop handler 357 btstack_run_loop_remove_data_source(&transport_data_source); 358 359 // then close device 360 close(transport_data_source.source.fd); 361 transport_data_source.source.fd = -1; 362 return 0; 363 } 364 365 static void btstack_uart_posix_set_block_received( void (*block_handler)(void)){ 366 block_received = block_handler; 367 } 368 369 static void btstack_uart_posix_set_block_sent( void (*block_handler)(void)){ 370 block_sent = block_handler; 371 } 372 373 static void btstack_uart_posix_send_block(const uint8_t *data, uint16_t size){ 374 // setup async write 375 write_bytes_data = data; 376 write_bytes_len = size; 377 378 // go 379 // btstack_uart_posix_process_write(&transport_data_source); 380 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE); 381 } 382 383 static void btstack_uart_posix_receive_block(uint8_t *buffer, uint16_t len){ 384 read_bytes_data = buffer; 385 read_bytes_len = len; 386 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ); 387 388 // go 389 // btstack_uart_posix_process_read(&transport_data_source); 390 } 391 392 // static void btstack_uart_posix_set_sleep(uint8_t sleep){ 393 // } 394 // static void btstack_uart_posix_set_csr_irq_handler( void (*csr_irq_handler)(void)){ 395 // } 396 397 static const btstack_uart_block_t btstack_uart_posix = { 398 /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_posix_init, 399 /* int (*open)(void); */ &btstack_uart_posix_open, 400 /* int (*close)(void); */ &btstack_uart_posix_close_new, 401 /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_posix_set_block_received, 402 /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_posix_set_block_sent, 403 /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_posix_set_baudrate, 404 /* int (*set_parity)(int parity); */ &btstack_uart_posix_set_parity, 405 /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_posix_set_flowcontrol, 406 /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_posix_receive_block, 407 /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_posix_send_block, 408 /* int (*get_supported_sleep_modes); */ NULL, 409 /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL, 410 /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL, 411 NULL, NULL, NULL, NULL, 412 }; 413 414 const btstack_uart_block_t * btstack_uart_posix_instance(void){ 415 return &btstack_uart_posix; 416 } 417