diff --git a/src/hci_transport_h4.c b/src/hci_transport_h4.c index 70ca9b4cc..530f990da 100644 --- a/src/hci_transport_h4.c +++ b/src/hci_transport_h4.c @@ -41,28 +41,41 @@ #include /* UNIX standard function definitions */ #include #include +#include #include "hci.h" #include "hci_transport.h" #include "hci_dump.h" +// #define USE_HCI_READER_THREAD + typedef enum { H4_W4_PACKET_TYPE, H4_W4_EVENT_HEADER, - H4_W4_EVENT_PAYLOAD, H4_W4_ACL_HEADER, - H4_W4_ACL_PAYLOAD + H4_W4_PAYLOAD, + H4_W4_PICKUP } H4_STATE; typedef struct hci_transport_h4 { hci_transport_t transport; data_source_t *ds; + int uart_fd; // different from ds->fd for HCI reader thread + +#ifdef USE_HCI_READER_THREAD + // synchronization facilities for dedicated reader thread + int pipe_fds[2]; + pthread_mutex_t mutex; + pthread_cond_t cond; +#endif } hci_transport_h4_t; // single instance static hci_transport_h4_t * hci_transport_h4 = NULL; static int h4_process(struct data_source *ds); +static void *h4_reader(void *context); +static int h4_reader_process(struct data_source *ds); static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size); static hci_uart_config_t *hci_uart_config; @@ -73,37 +86,18 @@ static H4_STATE h4_state; static int bytes_to_read; static int read_pos; // static uint8_t hci_event_buffer[255+2]; // maximal payload + 2 bytes header -static uint8_t hci_packet[HCI_ACL_3DH5_SIZE]; // bigger than largest packet - -#ifdef TEST_LONG_INVALID_REMOTE_NAME -// test event with remote name of 255 bytes length -const uint8_t remoteNameEvent[] = { 0x07, 0xFF, 0x00, 0xC4, 0xC6, 0x65, 0x5A, 0x12, 0x00, 0x4D, 0x69, - 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0xAE, 0x20, 0x57, 0x69, 0x72, 0x65, 0x6C, 0x65, - 0x73, 0x73, 0x20, 0x4E, 0x6F, 0x74, 0x65, 0x62, 0x6F, 0x6F, 0x6B, 0x20, 0x50, 0x72, 0x65, - 0x73, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x38, 0x30, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const int remoteNameEventSize = sizeof(remoteNameEvent); -#endif +static uint8_t hci_packet[1+HCI_ACL_3DH5_SIZE]; // bigger than largest packet // prototypes static int h4_open(void *transport_config){ hci_uart_config = (hci_uart_config_t*) transport_config; struct termios toptions; - int fd = open(hci_uart_config->device_name, O_RDWR | O_NOCTTY | O_NDELAY); + int flags = O_RDWR | O_NOCTTY; +#ifndef USE_HCI_READER_THREAD + flags |= O_NONBLOCK; +#endif + int fd = open(hci_uart_config->device_name, flags); if (fd == -1) { perror("init_serialport: Unable to open port "); perror(hci_uart_config->device_name); @@ -162,9 +156,27 @@ static int h4_open(void *transport_config){ // set up data_source hci_transport_h4->ds = malloc(sizeof(data_source_t)); - if (!hci_transport_h4) return -1; + if (!hci_transport_h4->ds) return -1; + hci_transport_h4->uart_fd = fd; + +#ifdef USE_HCI_READER_THREAD + // init synchronization tools + pthread_mutex_init(&hci_transport_h4->mutex, NULL); + pthread_cond_init(&hci_transport_h4->cond, NULL); + + // create pipe + pipe(hci_transport_h4->pipe_fds); + + // create reader thread + pthread_t hci_reader_thread; + pthread_create(&hci_reader_thread, NULL, &h4_reader, NULL); + + hci_transport_h4->ds->fd = hci_transport_h4->pipe_fds[0]; + hci_transport_h4->ds->process = h4_reader_process; +#else hci_transport_h4->ds->fd = fd; hci_transport_h4->ds->process = h4_process; +#endif run_loop_add_data_source(hci_transport_h4->ds); // init state machine @@ -190,12 +202,12 @@ static int h4_close(){ static int h4_send_packet(uint8_t packet_type, uint8_t * packet, int size){ if (hci_transport_h4->ds == NULL) return -1; - if (hci_transport_h4->ds->fd == 0) return -1; + if (hci_transport_h4->uart_fd == 0) return -1; hci_dump_packet( (uint8_t) packet_type, 0, packet, size); - write(hci_transport_h4->ds->fd, &packet_type, 1); + write(hci_transport_h4->uart_fd, &packet_type, 1); char *data = (char*) packet; while (size > 0) { - int bytes_written = write(hci_transport_h4->ds->fd, data, size); + int bytes_written = write(hci_transport_h4->uart_fd, data, size); if (bytes_written < 0) { usleep(5000); continue; @@ -210,30 +222,24 @@ static void h4_register_packet_handler(void (*handler)(uint8_t packet_type, ui packet_handler = handler; } -static int h4_process(struct data_source *ds) { - if (hci_transport_h4->ds->fd == 0) return -1; - - // read up to bytes_to_read data in - int bytes_read = read(hci_transport_h4->ds->fd, &hci_packet[read_pos], bytes_to_read); - if (bytes_read < 0) { - return bytes_read; - } - bytes_to_read -= bytes_read; - read_pos += bytes_read; - if (bytes_to_read > 0) { - return 0; - } +static void h4_deliver_packet(){ + if (read_pos < 3) return; // sanity check + hci_dump_packet( hci_packet[0], 1, &hci_packet[1], read_pos-1); + packet_handler(hci_packet[0], &hci_packet[1], read_pos-1); - // act + h4_state = H4_W4_PACKET_TYPE; + read_pos = 0; + bytes_to_read = 1; +} + +static void h4_statemachine(){ switch (h4_state) { case H4_W4_PACKET_TYPE: if (hci_packet[0] == HCI_EVENT_PACKET){ - read_pos = 0; bytes_to_read = HCI_EVENT_PKT_HDR; h4_state = H4_W4_EVENT_HEADER; } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){ - read_pos = 0; bytes_to_read = HCI_ACL_DATA_PKT_HDR; h4_state = H4_W4_ACL_HEADER; } else { @@ -244,41 +250,91 @@ static int h4_process(struct data_source *ds) { break; case H4_W4_EVENT_HEADER: - bytes_to_read = hci_packet[1]; - h4_state = H4_W4_EVENT_PAYLOAD; - break; - - case H4_W4_EVENT_PAYLOAD: - -#ifdef TEST_LONG_INVALID_REMOTE_NAME - if (hci_packet[0] == HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE){ - hci_packet[1] = remoteNameEvent[1]; - memcpy( &hci_packet[9], &remoteNameEvent[9], remoteNameEventSize); - read_pos = remoteNameEventSize; - } -#endif - hci_dump_packet( HCI_EVENT_PACKET, 1, hci_packet, read_pos); - packet_handler(HCI_EVENT_PACKET, hci_packet, read_pos); - h4_state = H4_W4_PACKET_TYPE; - read_pos = 0; - bytes_to_read = 1; + bytes_to_read = hci_packet[2]; + h4_state = H4_W4_PAYLOAD; break; case H4_W4_ACL_HEADER: - bytes_to_read = READ_BT_16( hci_packet, 2); - h4_state = H4_W4_ACL_PAYLOAD; + bytes_to_read = READ_BT_16( hci_packet, 3); + h4_state = H4_W4_PAYLOAD; break; - case H4_W4_ACL_PAYLOAD: - hci_dump_packet( HCI_ACL_DATA_PACKET, 1, hci_packet, read_pos); - packet_handler(HCI_ACL_DATA_PACKET, hci_packet, read_pos); + case H4_W4_PAYLOAD: +#ifdef USE_HCI_READER_THREAD + h4_state = H4_W4_PICKUP; +#else + h4_deliver_packet(); +#endif + break; + } +} + +static int h4_process(struct data_source *ds) { + if (hci_transport_h4->uart_fd == 0) return -1; + + // read up to bytes_to_read data in + int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read); + if (bytes_read < 0) { + return bytes_read; + } + bytes_to_read -= bytes_read; + read_pos += bytes_read; + if (bytes_to_read > 0) { + return 0; + } + + h4_statemachine(); + return 0; +} + +static int h4_reader_process(struct data_source *ds) { + // get token + char token; + read(hci_transport_h4->pipe_fds[0], &token, 1); + + // hci_reader received complete packet, just pick it up + h4_deliver_packet(); + + // un-block reader + pthread_mutex_lock(&hci_transport_h4->mutex); + pthread_cond_signal(&hci_transport_h4->cond); + pthread_mutex_unlock(&hci_transport_h4->mutex); + return 0; +} + +#ifdef USE_HCI_READER_THREAD +static void *h4_reader(void *context){ + while(1){ + // read up to bytes_to_read data in + int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read); + // error + if (bytes_read < 0) { h4_state = H4_W4_PACKET_TYPE; read_pos = 0; bytes_to_read = 1; - break; - } - return 0; + continue; + } + + bytes_to_read -= bytes_read; + read_pos += bytes_read; + + if (bytes_to_read > 0) continue; + + h4_statemachine(); + + if (h4_state != H4_W4_PICKUP) continue; + + // notify main thread + char data = 'h'; + write(hci_transport_h4->pipe_fds[1], &data, 1); + + // wait for response + pthread_mutex_lock(&hci_transport_h4->mutex); + pthread_cond_wait(&hci_transport_h4->cond,&hci_transport_h4->mutex); + pthread_mutex_unlock(&hci_transport_h4->mutex); + } } +#endif static const char * h4_get_transport_name(){ return "H4";