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