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