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