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 // single instance 26 static hci_transport_t * hci_transport_h4 = NULL; 27 28 static void dummy_handler(uint8_t *packet, int size); 29 static hci_uart_config_t *hci_uart_config; 30 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 int 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 // set up data_source 104 hci_transport_h4->ds.fd = fd; 105 106 // init state machine 107 bytes_to_read = 1; 108 h4_state = H4_W4_PACKET_TYPE; 109 read_pos = 0; 110 111 return 0; 112 } 113 114 static int h4_close(){ 115 close(hci_transport_h4->ds.fd); 116 hci_transport_h4->ds.fd = 0; 117 return 0; 118 } 119 120 static int h4_send_cmd_packet(uint8_t *packet, int size){ 121 if (hci_transport_h4->ds.fd == 0) return -1; 122 123 printf("CMD: "); 124 hexdump(packet, size); 125 126 char *data = (char*) packet; 127 char packet_type = HCI_COMMAND_DATA_PACKET; 128 129 hci_dump_packet( (uint8_t) packet_type, 0, packet, size); 130 131 write(hci_transport_h4->ds.fd, &packet_type, 1); 132 while (size > 0) { 133 int bytes_written = write(hci_transport_h4->ds.fd, data, size); 134 if (bytes_written < 0) { 135 return bytes_written; 136 } 137 data += bytes_written; 138 size -= bytes_written; 139 } 140 return 0; 141 } 142 143 static int h4_send_acl_packet(uint8_t *packet, int size){ 144 if (hci_transport_h4->ds.fd == 0) return -1; 145 146 printf("ACL> "); 147 hexdump(packet, size); 148 149 char *data = (char*) packet; 150 char packet_type = HCI_ACL_DATA_PACKET; 151 152 hci_dump_packet( (uint8_t) packet_type, 0, packet, size); 153 154 write(hci_transport_h4->ds.fd, &packet_type, 1); 155 while (size > 0) { 156 int bytes_written = write(hci_transport_h4->ds.fd, data, size); 157 if (bytes_written < 0) { 158 return bytes_written; 159 } 160 data += bytes_written; 161 size -= bytes_written; 162 } 163 return 0; 164 } 165 166 static void h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){ 167 event_packet_handler = handler; 168 } 169 170 static void h4_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size)){ 171 acl_packet_handler = handler; 172 } 173 174 static int h4_process(struct data_source *ds, int ready) { 175 if (hci_transport_h4->ds.fd == 0) return -1; 176 177 // read up to bytes_to_read data in 178 int bytes_read = read(hci_transport_h4->ds.fd, &hci_packet[read_pos], bytes_to_read); 179 if (bytes_read < 0) { 180 return bytes_read; 181 } 182 // printf("Bytes read: %u\n", bytes_read); 183 bytes_to_read -= bytes_read; 184 read_pos += bytes_read; 185 if (bytes_to_read > 0) { 186 return 0; 187 } 188 189 // act 190 switch (h4_state) { 191 case H4_W4_PACKET_TYPE: 192 if (hci_packet[0] == HCI_EVENT_PACKET){ 193 read_pos = 0; 194 bytes_to_read = HCI_EVENT_PKT_HDR; 195 h4_state = H4_W4_EVENT_HEADER; 196 } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){ 197 read_pos = 0; 198 bytes_to_read = HCI_ACL_DATA_PKT_HDR; 199 h4_state = H4_W4_ACL_HEADER; 200 } else { 201 } 202 break; 203 case H4_W4_EVENT_HEADER: 204 bytes_to_read = hci_packet[1]; 205 h4_state = H4_W4_EVENT_PAYLOAD; 206 break; 207 case H4_W4_EVENT_PAYLOAD: 208 printf("EVT: "); 209 hexdump(hci_packet, read_pos); 210 211 hci_dump_packet( HCI_EVENT_PACKET, 1, hci_packet, read_pos); 212 213 event_packet_handler(hci_packet, read_pos); 214 h4_state = H4_W4_PACKET_TYPE; 215 read_pos = 0; 216 bytes_to_read = 1; 217 break; 218 case H4_W4_ACL_HEADER: 219 bytes_to_read = READ_BT_16( hci_packet, 2); 220 h4_state = H4_W4_ACL_PAYLOAD; 221 break; 222 case H4_W4_ACL_PAYLOAD: 223 printf("<ACL "); 224 hexdump(hci_packet, read_pos); 225 226 hci_dump_packet( HCI_ACL_DATA_PACKET, 1, hci_packet, read_pos); 227 228 acl_packet_handler(hci_packet, read_pos); 229 h4_state = H4_W4_PACKET_TYPE; 230 read_pos = 0; 231 bytes_to_read = 1; 232 break; 233 } 234 return 0; 235 } 236 237 static const char * h4_get_transport_name(){ 238 return "H4"; 239 } 240 241 static void dummy_handler(uint8_t *packet, int size){ 242 } 243 244 // get h4 singleton 245 hci_transport_t * hci_transport_h4_instance() { 246 if (hci_transport_h4 == NULL) { 247 hci_transport_h4 = malloc( sizeof(hci_transport_t)); 248 hci_transport_h4->ds.fd = 0; 249 hci_transport_h4->ds.process = h4_process; 250 hci_transport_h4->open = h4_open; 251 hci_transport_h4->close = h4_close; 252 hci_transport_h4->send_cmd_packet = h4_send_cmd_packet; 253 hci_transport_h4->send_acl_packet = h4_send_acl_packet; 254 hci_transport_h4->register_event_packet_handler = h4_register_event_packet_handler; 255 hci_transport_h4->register_acl_packet_handler = h4_register_acl_packet_handler; 256 hci_transport_h4->get_transport_name = h4_get_transport_name; 257 } 258 return hci_transport_h4; 259 } 260