xref: /btstack/src/hci_transport_h4.c (revision 7966267251b9debd0b0cb126c2187747faa073f9)
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