1 /* 2 * hci_h4_transport.c 3 * 4 * HCI Transport API implementation for basic H4 protocol 5 * 6 * Created by Matthias Ringwald on 4/29/09. 7 */ 8 #include <termios.h> /* POSIX terminal control definitions */ 9 #include <fcntl.h> /* File control definitions */ 10 #include <unistd.h> /* UNIX standard function definitions */ 11 #include <stdio.h> 12 13 #include "hci.h" 14 #include "hci_transport_h4.h" 15 #include "hci_dump.h" 16 17 typedef enum { 18 H4_W4_PACKET_TYPE, 19 H4_W4_EVENT_HEADER, 20 H4_W4_EVENT_PAYLOAD, 21 H4_W4_ACL_HEADER, 22 H4_W4_ACL_PAYLOAD 23 } H4_STATE; 24 25 typedef struct hci_transport_h4 { 26 hci_transport_t transport; 27 data_source_t *ds; 28 } hci_transport_h4_t; 29 30 // single instance 31 static hci_transport_h4_t * hci_transport_h4 = NULL; 32 33 static int h4_process(struct data_source *ds); 34 static void dummy_handler(uint8_t *packet, int size); 35 static hci_uart_config_t *hci_uart_config; 36 37 static void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler; 38 static void (*acl_packet_handler) (uint8_t *packet, int size) = dummy_handler; 39 40 // packet reader state machine 41 static H4_STATE h4_state; 42 static int bytes_to_read; 43 static int read_pos; 44 // static uint8_t hci_event_buffer[255+2]; // maximal payload + 2 bytes header 45 static uint8_t hci_packet[400]; // bigger than largest packet 46 47 // prototypes 48 static int h4_open(void *transport_config){ 49 hci_uart_config = (hci_uart_config_t*) transport_config; 50 struct termios toptions; 51 int fd = open(hci_uart_config->device_name, O_RDWR | O_NOCTTY | O_NDELAY); 52 if (fd == -1) { 53 perror("init_serialport: Unable to open port "); 54 perror(hci_uart_config->device_name); 55 return -1; 56 } 57 58 if (tcgetattr(fd, &toptions) < 0) { 59 perror("init_serialport: Couldn't get term attributes"); 60 return -1; 61 } 62 speed_t brate = hci_uart_config->baudrate; // let you override switch below if needed 63 switch(hci_uart_config->baudrate) { 64 case 57600: brate=B57600; break; 65 case 115200: brate=B115200; break; 66 #ifdef B230400 67 case 230400: brate=B230400; break; 68 #endif 69 #ifdef B460800 70 case 460800: brate=B460800; break; 71 #endif 72 #ifdef B921600 73 case 921600: brate=B921600; break; 74 #endif 75 } 76 cfsetispeed(&toptions, brate); 77 cfsetospeed(&toptions, brate); 78 79 // 8N1 80 toptions.c_cflag &= ~PARENB; 81 toptions.c_cflag &= ~CSTOPB; 82 toptions.c_cflag &= ~CSIZE; 83 toptions.c_cflag |= CS8; 84 85 if (hci_uart_config->flowcontrol) { 86 // with flow control 87 toptions.c_cflag |= CRTSCTS; 88 } else { 89 // no flow control 90 toptions.c_cflag &= ~CRTSCTS; 91 } 92 93 toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines 94 toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl 95 96 toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw 97 toptions.c_oflag &= ~OPOST; // make raw 98 99 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html 100 toptions.c_cc[VMIN] = 1; 101 toptions.c_cc[VTIME] = 0; 102 103 if( tcsetattr(fd, TCSANOW, &toptions) < 0) { 104 perror("init_serialport: Couldn't set term attributes"); 105 return -1; 106 } 107 108 // set up data_source 109 hci_transport_h4->ds = malloc(sizeof(data_source_t)); 110 if (!hci_transport_h4) return -1; 111 hci_transport_h4->ds->fd = fd; 112 hci_transport_h4->ds->process = h4_process; 113 run_loop_add_data_source(hci_transport_h4->ds); 114 115 // init state machine 116 bytes_to_read = 1; 117 h4_state = H4_W4_PACKET_TYPE; 118 read_pos = 0; 119 120 return 0; 121 } 122 123 static int h4_close(){ 124 // first remove run loop handler 125 run_loop_remove_data_source(hci_transport_h4->ds); 126 127 // close device 128 close(hci_transport_h4->ds->fd); 129 free(hci_transport_h4->ds); 130 131 // free struct 132 hci_transport_h4->ds = NULL; 133 return 0; 134 } 135 136 static int h4_send_cmd_packet(uint8_t *packet, int size){ 137 if (hci_transport_h4->ds == NULL) return -1; 138 if (hci_transport_h4->ds->fd == 0) return -1; 139 char *data = (char*) packet; 140 char packet_type = HCI_COMMAND_DATA_PACKET; 141 142 hci_dump_packet( (uint8_t) packet_type, 0, packet, size); 143 144 write(hci_transport_h4->ds->fd, &packet_type, 1); 145 while (size > 0) { 146 int bytes_written = write(hci_transport_h4->ds->fd, data, size); 147 if (bytes_written < 0) { 148 return bytes_written; 149 } 150 data += bytes_written; 151 size -= bytes_written; 152 } 153 return 0; 154 } 155 156 static int h4_send_acl_packet(uint8_t *packet, int size){ 157 if (hci_transport_h4->ds->fd == 0) return -1; 158 159 char *data = (char*) packet; 160 char packet_type = HCI_ACL_DATA_PACKET; 161 162 hci_dump_packet( (uint8_t) packet_type, 0, packet, size); 163 164 write(hci_transport_h4->ds->fd, &packet_type, 1); 165 while (size > 0) { 166 int bytes_written = write(hci_transport_h4->ds->fd, data, size); 167 if (bytes_written < 0) { 168 return bytes_written; 169 } 170 data += bytes_written; 171 size -= bytes_written; 172 } 173 return 0; 174 } 175 176 static void h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){ 177 event_packet_handler = handler; 178 } 179 180 static void h4_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size)){ 181 acl_packet_handler = handler; 182 } 183 184 static int h4_process(struct data_source *ds) { 185 if (hci_transport_h4->ds->fd == 0) return -1; 186 187 // read up to bytes_to_read data in 188 int bytes_read = read(hci_transport_h4->ds->fd, &hci_packet[read_pos], bytes_to_read); 189 if (bytes_read < 0) { 190 return bytes_read; 191 } 192 // printf("Bytes read: %u\n", bytes_read); 193 bytes_to_read -= bytes_read; 194 read_pos += bytes_read; 195 if (bytes_to_read > 0) { 196 return 0; 197 } 198 199 // act 200 switch (h4_state) { 201 case H4_W4_PACKET_TYPE: 202 if (hci_packet[0] == HCI_EVENT_PACKET){ 203 read_pos = 0; 204 bytes_to_read = HCI_EVENT_PKT_HDR; 205 h4_state = H4_W4_EVENT_HEADER; 206 } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){ 207 read_pos = 0; 208 bytes_to_read = HCI_ACL_DATA_PKT_HDR; 209 h4_state = H4_W4_ACL_HEADER; 210 } else { 211 } 212 break; 213 case H4_W4_EVENT_HEADER: 214 bytes_to_read = hci_packet[1]; 215 h4_state = H4_W4_EVENT_PAYLOAD; 216 break; 217 case H4_W4_EVENT_PAYLOAD: 218 hci_dump_packet( HCI_EVENT_PACKET, 1, hci_packet, read_pos); 219 event_packet_handler(hci_packet, read_pos); 220 h4_state = H4_W4_PACKET_TYPE; 221 read_pos = 0; 222 bytes_to_read = 1; 223 break; 224 case H4_W4_ACL_HEADER: 225 bytes_to_read = READ_BT_16( hci_packet, 2); 226 h4_state = H4_W4_ACL_PAYLOAD; 227 break; 228 case H4_W4_ACL_PAYLOAD: 229 hci_dump_packet( HCI_ACL_DATA_PACKET, 1, hci_packet, read_pos); 230 231 acl_packet_handler(hci_packet, read_pos); 232 h4_state = H4_W4_PACKET_TYPE; 233 read_pos = 0; 234 bytes_to_read = 1; 235 break; 236 } 237 return 0; 238 } 239 240 static const char * h4_get_transport_name(){ 241 return "H4"; 242 } 243 244 static void dummy_handler(uint8_t *packet, int size){ 245 } 246 247 // get h4 singleton 248 hci_transport_t * hci_transport_h4_instance() { 249 if (hci_transport_h4 == NULL) { 250 hci_transport_h4 = malloc( sizeof(hci_transport_h4_t)); 251 hci_transport_h4->ds = NULL; 252 hci_transport_h4->transport.open = h4_open; 253 hci_transport_h4->transport.close = h4_close; 254 hci_transport_h4->transport.send_cmd_packet = h4_send_cmd_packet; 255 hci_transport_h4->transport.send_acl_packet = h4_send_acl_packet; 256 hci_transport_h4->transport.register_event_packet_handler = h4_register_event_packet_handler; 257 hci_transport_h4->transport.register_acl_packet_handler = h4_register_acl_packet_handler; 258 hci_transport_h4->transport.get_transport_name = h4_get_transport_name; 259 } 260 return (hci_transport_t *) hci_transport_h4; 261 } 262