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