1 /* 2 * Copyright (C) 2009 by Matthias Ringwald 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 * 17 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 21 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 /* 33 * hci_h4_transport.c 34 * 35 * HCI Transport API implementation for basic H4 protocol 36 * 37 * Created by Matthias Ringwald on 4/29/09. 38 */ 39 #include <termios.h> /* POSIX terminal control definitions */ 40 #include <fcntl.h> /* File control definitions */ 41 #include <unistd.h> /* UNIX standard function definitions */ 42 #include <stdio.h> 43 #include <string.h> 44 #include <pthread.h> 45 46 #include "debug.h" 47 #include "hci.h" 48 #include "hci_transport.h" 49 #include "hci_dump.h" 50 51 52 // determine size of receive buffer 53 // use one extra byte to guarantee zero terminated device name in remote name event 54 #if (HCI_ACL_DATA_PKT_HDR + HCI_ACL_BUFFER_SIZE) > (HCI_EVENT_PKT_HDR + HCI_EVENT_PKT_SIZE + 1) 55 #define HCI_PACKET_BUFFER_SIZE (HCI_ACL_DATA_PKT_HDR + HCI_ACL_BUFFER_SIZE) 56 #else 57 #define HCI_PACKET_BUFFER_SIZE (HCI_EVENT_PKT_HDR + HCI_EVENT_PKT_SIZE + 1) 58 #endif 59 60 // #define USE_HCI_READER_THREAD 61 62 typedef enum { 63 H4_W4_PACKET_TYPE, 64 H4_W4_EVENT_HEADER, 65 H4_W4_ACL_HEADER, 66 H4_W4_PAYLOAD, 67 H4_W4_PICKUP 68 } H4_STATE; 69 70 typedef struct hci_transport_h4 { 71 hci_transport_t transport; 72 data_source_t *ds; 73 int uart_fd; // different from ds->fd for HCI reader thread 74 75 #ifdef USE_HCI_READER_THREAD 76 // synchronization facilities for dedicated reader thread 77 int pipe_fds[2]; 78 pthread_mutex_t mutex; 79 pthread_cond_t cond; 80 #endif 81 } hci_transport_h4_t; 82 83 // single instance 84 static hci_transport_h4_t * hci_transport_h4 = NULL; 85 86 static int h4_process(struct data_source *ds); 87 static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size); 88 static hci_uart_config_t *hci_uart_config; 89 90 #ifdef USE_HCI_READER_THREAD 91 static void *h4_reader(void *context); 92 static int h4_reader_process(struct data_source *ds); 93 #endif 94 95 96 static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_handler; 97 98 // packet reader state machine 99 static H4_STATE h4_state; 100 static int bytes_to_read; 101 static int read_pos; 102 103 static uint8_t hci_packet[1+HCI_PACKET_BUFFER_SIZE]; // packet type + max(acl header + acl payload, event header + event data) 104 105 // prototypes 106 static int h4_open(void *transport_config){ 107 hci_uart_config = (hci_uart_config_t*) transport_config; 108 struct termios toptions; 109 int flags = O_RDWR | O_NOCTTY; 110 #ifndef USE_HCI_READER_THREAD 111 flags |= O_NONBLOCK; 112 #endif 113 int fd = open(hci_uart_config->device_name, flags); 114 if (fd == -1) { 115 perror("init_serialport: Unable to open port "); 116 perror(hci_uart_config->device_name); 117 return -1; 118 } 119 120 if (tcgetattr(fd, &toptions) < 0) { 121 perror("init_serialport: Couldn't get term attributes"); 122 return -1; 123 } 124 speed_t brate = hci_uart_config->baudrate_init; // let you override switch below if needed 125 switch(hci_uart_config->baudrate_init) { 126 case 57600: brate=B57600; break; 127 case 115200: brate=B115200; break; 128 #ifdef B230400 129 case 230400: brate=B230400; break; 130 #endif 131 #ifdef B460800 132 case 460800: brate=B460800; break; 133 #endif 134 #ifdef B921600 135 case 921600: brate=B921600; break; 136 #endif 137 } 138 cfsetispeed(&toptions, brate); 139 cfsetospeed(&toptions, brate); 140 141 // 8N1 142 toptions.c_cflag &= ~PARENB; 143 toptions.c_cflag &= ~CSTOPB; 144 toptions.c_cflag &= ~CSIZE; 145 toptions.c_cflag |= CS8; 146 147 if (hci_uart_config->flowcontrol) { 148 // with flow control 149 toptions.c_cflag |= CRTSCTS; 150 } else { 151 // no flow control 152 toptions.c_cflag &= ~CRTSCTS; 153 } 154 155 toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines 156 toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl 157 158 toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw 159 toptions.c_oflag &= ~OPOST; // make raw 160 161 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html 162 toptions.c_cc[VMIN] = 1; 163 toptions.c_cc[VTIME] = 0; 164 165 if( tcsetattr(fd, TCSANOW, &toptions) < 0) { 166 perror("init_serialport: Couldn't set term attributes"); 167 return -1; 168 } 169 170 // set up data_source 171 hci_transport_h4->ds = malloc(sizeof(data_source_t)); 172 if (!hci_transport_h4->ds) return -1; 173 hci_transport_h4->uart_fd = fd; 174 175 #ifdef USE_HCI_READER_THREAD 176 // init synchronization tools 177 pthread_mutex_init(&hci_transport_h4->mutex, NULL); 178 pthread_cond_init(&hci_transport_h4->cond, NULL); 179 180 // create pipe 181 pipe(hci_transport_h4->pipe_fds); 182 183 // create reader thread 184 pthread_t hci_reader_thread; 185 pthread_create(&hci_reader_thread, NULL, &h4_reader, NULL); 186 187 hci_transport_h4->ds->fd = hci_transport_h4->pipe_fds[0]; 188 hci_transport_h4->ds->process = h4_reader_process; 189 #else 190 hci_transport_h4->ds->fd = fd; 191 hci_transport_h4->ds->process = h4_process; 192 #endif 193 run_loop_add_data_source(hci_transport_h4->ds); 194 195 // init state machine 196 bytes_to_read = 1; 197 h4_state = H4_W4_PACKET_TYPE; 198 read_pos = 0; 199 200 return 0; 201 } 202 203 static int h4_close(void *transport_config){ 204 // first remove run loop handler 205 run_loop_remove_data_source(hci_transport_h4->ds); 206 207 // close device 208 close(hci_transport_h4->ds->fd); 209 210 // free struct 211 free(hci_transport_h4->ds); 212 hci_transport_h4->ds = NULL; 213 return 0; 214 } 215 216 static int h4_send_packet(uint8_t packet_type, uint8_t * packet, int size){ 217 if (hci_transport_h4->ds == NULL) return -1; 218 if (hci_transport_h4->uart_fd == 0) return -1; 219 hci_dump_packet( (uint8_t) packet_type, 0, packet, size); 220 char *data = (char*) packet; 221 int bytes_written = write(hci_transport_h4->uart_fd, &packet_type, 1); 222 while (bytes_written < 1) { 223 usleep(5000); 224 bytes_written = write(hci_transport_h4->uart_fd, &packet_type, 1); 225 }; 226 while (size > 0) { 227 int bytes_written = write(hci_transport_h4->uart_fd, data, size); 228 if (bytes_written < 0) { 229 usleep(5000); 230 continue; 231 } 232 data += bytes_written; 233 size -= bytes_written; 234 } 235 return 0; 236 } 237 238 static void h4_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){ 239 packet_handler = handler; 240 } 241 242 static void h4_deliver_packet(void){ 243 if (read_pos < 3) return; // sanity check 244 hci_dump_packet( hci_packet[0], 1, &hci_packet[1], read_pos-1); 245 packet_handler(hci_packet[0], &hci_packet[1], read_pos-1); 246 247 h4_state = H4_W4_PACKET_TYPE; 248 read_pos = 0; 249 bytes_to_read = 1; 250 } 251 252 static void h4_statemachine(void){ 253 switch (h4_state) { 254 255 case H4_W4_PACKET_TYPE: 256 if (hci_packet[0] == HCI_EVENT_PACKET){ 257 bytes_to_read = HCI_EVENT_PKT_HDR; 258 h4_state = H4_W4_EVENT_HEADER; 259 } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){ 260 bytes_to_read = HCI_ACL_DATA_PKT_HDR; 261 h4_state = H4_W4_ACL_HEADER; 262 } else { 263 log_error("h4_process: invalid packet type 0x%02x\n", hci_packet[0]); 264 read_pos = 0; 265 bytes_to_read = 1; 266 } 267 break; 268 269 case H4_W4_EVENT_HEADER: 270 bytes_to_read = hci_packet[2]; 271 h4_state = H4_W4_PAYLOAD; 272 break; 273 274 case H4_W4_ACL_HEADER: 275 bytes_to_read = READ_BT_16( hci_packet, 3); 276 h4_state = H4_W4_PAYLOAD; 277 break; 278 279 case H4_W4_PAYLOAD: 280 #ifdef USE_HCI_READER_THREAD 281 h4_state = H4_W4_PICKUP; 282 #else 283 h4_deliver_packet(); 284 #endif 285 break; 286 default: 287 break; 288 } 289 } 290 291 static int h4_process(struct data_source *ds) { 292 if (hci_transport_h4->uart_fd == 0) return -1; 293 294 int read_now = bytes_to_read; 295 // if (read_now > 100) { 296 // read_now = 100; 297 // } 298 299 // read up to bytes_to_read data in 300 ssize_t bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], read_now); 301 // printf("h4_process: bytes read %u\n", bytes_read); 302 if (bytes_read < 0) { 303 return bytes_read; 304 } 305 306 // hexdump(&hci_packet[read_pos], bytes_read); 307 308 bytes_to_read -= bytes_read; 309 read_pos += bytes_read; 310 if (bytes_to_read > 0) { 311 return 0; 312 } 313 314 h4_statemachine(); 315 return 0; 316 } 317 318 #ifdef USE_HCI_READER_THREAD 319 static int h4_reader_process(struct data_source *ds) { 320 // get token 321 char token; 322 int tokens_read = read(hci_transport_h4->pipe_fds[0], &token, 1); 323 if (tokens_read < 1) { 324 return 0; 325 } 326 327 // hci_reader received complete packet, just pick it up 328 h4_deliver_packet(); 329 330 // un-block reader 331 pthread_mutex_lock(&hci_transport_h4->mutex); 332 pthread_cond_signal(&hci_transport_h4->cond); 333 pthread_mutex_unlock(&hci_transport_h4->mutex); 334 return 0; 335 } 336 337 static void *h4_reader(void *context){ 338 while(1){ 339 // read up to bytes_to_read data in 340 int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read); 341 // error 342 if (bytes_read < 0) { 343 h4_state = H4_W4_PACKET_TYPE; 344 read_pos = 0; 345 bytes_to_read = 1; 346 continue; 347 } 348 349 bytes_to_read -= bytes_read; 350 read_pos += bytes_read; 351 352 if (bytes_to_read > 0) continue; 353 354 h4_statemachine(); 355 356 if (h4_state != H4_W4_PICKUP) continue; 357 358 // notify main thread 359 char data = 'h'; 360 write(hci_transport_h4->pipe_fds[1], &data, 1); 361 362 // wait for response 363 pthread_mutex_lock(&hci_transport_h4->mutex); 364 pthread_cond_wait(&hci_transport_h4->cond,&hci_transport_h4->mutex); 365 pthread_mutex_unlock(&hci_transport_h4->mutex); 366 } 367 } 368 #endif 369 370 static const char * h4_get_transport_name(void){ 371 return "H4"; 372 } 373 374 static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){ 375 } 376 377 // get h4 singleton 378 hci_transport_t * hci_transport_h4_instance() { 379 if (hci_transport_h4 == NULL) { 380 hci_transport_h4 = malloc( sizeof(hci_transport_h4_t)); 381 hci_transport_h4->ds = NULL; 382 hci_transport_h4->transport.open = h4_open; 383 hci_transport_h4->transport.close = h4_close; 384 hci_transport_h4->transport.send_packet = h4_send_packet; 385 hci_transport_h4->transport.register_packet_handler = h4_register_packet_handler; 386 hci_transport_h4->transport.get_transport_name = h4_get_transport_name; 387 hci_transport_h4->transport.set_baudrate = NULL; 388 hci_transport_h4->transport.can_send_packet_now = NULL; 389 } 390 return (hci_transport_t *) hci_transport_h4; 391 } 392