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 cfsetospeed(&toptions, brate); 207 cfsetispeed(&toptions, brate); 208 209 if( tcsetattr(fd, TCSANOW, &toptions) < 0) { 210 log_error("btstack_uart_posix_set_baudrate: Couldn't set term attributes"); 211 return -1; 212 } 213 #endif 214 #endif 215 return 0; 216 } 217 218 static void btstack_uart_posix_set_parity_option(struct termios * toptions, int parity){ 219 if (parity){ 220 // enable even parity 221 toptions->c_cflag |= PARENB; 222 } else { 223 // disable even parity 224 toptions->c_cflag &= ~PARENB; 225 } 226 } 227 228 static void btstack_uart_posix_set_flowcontrol_option(struct termios * toptions, int flowcontrol){ 229 if (flowcontrol) { 230 // with flow control 231 toptions->c_cflag |= CRTSCTS; 232 } else { 233 // no flow control 234 toptions->c_cflag &= ~CRTSCTS; 235 } 236 } 237 238 static int btstack_uart_posix_set_parity(int parity){ 239 int fd = transport_data_source.source.fd; 240 struct termios toptions; 241 if (tcgetattr(fd, &toptions) < 0) { 242 log_error("btstack_uart_posix_set_parity: Couldn't get term attributes"); 243 return -1; 244 } 245 btstack_uart_posix_set_parity_option(&toptions, parity); 246 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 247 log_error("posix_set_parity: Couldn't set term attributes"); 248 return -1; 249 } 250 return 0; 251 } 252 253 254 static int btstack_uart_posix_set_flowcontrol(int flowcontrol){ 255 int fd = transport_data_source.source.fd; 256 struct termios toptions; 257 if (tcgetattr(fd, &toptions) < 0) { 258 log_error("btstack_uart_posix_set_parity: Couldn't get term attributes"); 259 return -1; 260 } 261 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol); 262 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 263 log_error("posix_set_flowcontrol: Couldn't set term attributes"); 264 return -1; 265 } 266 return 0; 267 } 268 269 static int btstack_uart_posix_open(void){ 270 271 const char * device_name = uart_config->device_name; 272 const int flowcontrol = uart_config->flowcontrol; 273 const uint32_t baudrate = uart_config->baudrate; 274 275 struct termios toptions; 276 int flags = O_RDWR | O_NOCTTY | O_NONBLOCK; 277 int fd = open(device_name, flags); 278 if (fd == -1) { 279 log_error("posix_open: Unable to open port %s", device_name); 280 return -1; 281 } 282 283 if (tcgetattr(fd, &toptions) < 0) { 284 log_error("posix_open: Couldn't get term attributes"); 285 return -1; 286 } 287 288 cfmakeraw(&toptions); // make raw 289 290 // 8N1 291 toptions.c_cflag &= ~CSTOPB; 292 toptions.c_cflag |= CS8; 293 294 toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines 295 toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl 296 297 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html 298 toptions.c_cc[VMIN] = 1; 299 toptions.c_cc[VTIME] = 0; 300 301 // no parity 302 btstack_uart_posix_set_parity_option(&toptions, 0); 303 304 // flowcontrol 305 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol); 306 307 if(tcsetattr(fd, TCSANOW, &toptions) < 0) { 308 log_error("posix_open: Couldn't set term attributes"); 309 return -1; 310 } 311 312 // store fd in data source 313 transport_data_source.source.fd = fd; 314 315 // also set baudrate 316 if (btstack_uart_posix_set_baudrate(baudrate) < 0){ 317 return -1; 318 } 319 320 // set up data_source 321 btstack_run_loop_set_data_source_fd(&transport_data_source, fd); 322 btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_transport_h5_process); 323 btstack_run_loop_add_data_source(&transport_data_source); 324 325 // wait a bit - at least cheap FTDI232 clones might send the first byte out incorrectly 326 usleep(100000); 327 328 return 0; 329 } 330 331 static int btstack_uart_posix_close_new(void){ 332 333 // first remove run loop handler 334 btstack_run_loop_remove_data_source(&transport_data_source); 335 336 // then close device 337 close(transport_data_source.source.fd); 338 transport_data_source.source.fd = -1; 339 return 0; 340 } 341 342 static void btstack_uart_posix_set_block_received( void (*block_handler)(void)){ 343 block_received = block_handler; 344 } 345 346 static void btstack_uart_posix_set_block_sent( void (*block_handler)(void)){ 347 block_sent = block_handler; 348 } 349 350 static void btstack_uart_posix_send_block(const uint8_t *data, uint16_t size){ 351 // setup async write 352 write_bytes_data = data; 353 write_bytes_len = size; 354 355 // go 356 // btstack_uart_posix_process_write(&transport_data_source); 357 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE); 358 } 359 360 static void btstack_uart_posix_receive_block(uint8_t *buffer, uint16_t len){ 361 read_bytes_data = buffer; 362 read_bytes_len = len; 363 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ); 364 365 // go 366 // btstack_uart_posix_process_read(&transport_data_source); 367 } 368 369 // static void btstack_uart_posix_set_sleep(uint8_t sleep){ 370 // } 371 // static void btstack_uart_posix_set_csr_irq_handler( void (*csr_irq_handler)(void)){ 372 // } 373 374 static const btstack_uart_block_t btstack_uart_posix = { 375 /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_posix_init, 376 /* int (*open)(void); */ &btstack_uart_posix_open, 377 /* int (*close)(void); */ &btstack_uart_posix_close_new, 378 /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_posix_set_block_received, 379 /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_posix_set_block_sent, 380 /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_posix_set_baudrate, 381 /* int (*set_parity)(int parity); */ &btstack_uart_posix_set_parity, 382 /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_posix_set_flowcontrol, 383 /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_posix_receive_block, 384 /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_posix_send_block, 385 /* int (*get_supported_sleep_modes); */ NULL, 386 /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL, 387 /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL, 388 NULL, NULL, NULL, NULL, 389 }; 390 391 const btstack_uart_block_t * btstack_uart_posix_instance(void){ 392 return &btstack_uart_posix; 393 } 394