xref: /btstack/src/hci_transport_h4.c (revision 0c806b9a9eff48ca0ccca40dbf1db597c09c3b73)
1 /*
2  * Copyright (C) 2009 by Matthias Ringwald
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
21  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  */
31 
32 /*
33  *  hci_h4_transport.c
34  *
35  *  HCI Transport API implementation for basic H4 protocol
36  *
37  *  Created by Matthias Ringwald on 4/29/09.
38  */
39 #include <termios.h>  /* POSIX terminal control definitions */
40 #include <fcntl.h>    /* File control definitions */
41 #include <unistd.h>   /* UNIX standard function definitions */
42 #include <stdio.h>
43 #include <string.h>
44 #include <pthread.h>
45 
46 #include "hci.h"
47 #include "hci_transport.h"
48 #include "hci_dump.h"
49 
50 // #define USE_HCI_READER_THREAD
51 
52 typedef enum {
53     H4_W4_PACKET_TYPE,
54     H4_W4_EVENT_HEADER,
55     H4_W4_ACL_HEADER,
56     H4_W4_PAYLOAD,
57     H4_W4_PICKUP
58 } H4_STATE;
59 
60 typedef struct hci_transport_h4 {
61     hci_transport_t transport;
62     data_source_t *ds;
63     int uart_fd;    // different from ds->fd for HCI reader thread
64 
65 #ifdef USE_HCI_READER_THREAD
66     // synchronization facilities for dedicated reader thread
67     int pipe_fds[2];
68     pthread_mutex_t mutex;
69     pthread_cond_t cond;
70 #endif
71 } hci_transport_h4_t;
72 
73 // single instance
74 static hci_transport_h4_t * hci_transport_h4 = NULL;
75 
76 static int  h4_process(struct data_source *ds);
77 static void *h4_reader(void *context);
78 static int  h4_reader_process(struct data_source *ds);
79 static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
80 static      hci_uart_config_t *hci_uart_config;
81 
82 static  void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_handler;
83 
84 // packet reader state machine
85 static  H4_STATE h4_state;
86 static int bytes_to_read;
87 static int read_pos;
88 // static uint8_t hci_event_buffer[255+2]; // maximal payload + 2 bytes header
89 static uint8_t hci_packet[1+HCI_ACL_3DH5_SIZE]; // bigger than largest packet
90 
91 
92 // prototypes
93 static int    h4_open(void *transport_config){
94     hci_uart_config = (hci_uart_config_t*) transport_config;
95     struct termios toptions;
96     int flags = O_RDWR | O_NOCTTY;
97 #ifndef USE_HCI_READER_THREAD
98     flags |= O_NONBLOCK;
99 #endif
100     int fd = open(hci_uart_config->device_name, flags);
101     if (fd == -1)  {
102         perror("init_serialport: Unable to open port ");
103         perror(hci_uart_config->device_name);
104         return -1;
105     }
106 
107     if (tcgetattr(fd, &toptions) < 0) {
108         perror("init_serialport: Couldn't get term attributes");
109         return -1;
110     }
111     speed_t brate = hci_uart_config->baudrate; // let you override switch below if needed
112     switch(hci_uart_config->baudrate) {
113         case 57600:  brate=B57600;  break;
114         case 115200: brate=B115200; break;
115 #ifdef B230400
116         case 230400: brate=B230400; break;
117 #endif
118 #ifdef B460800
119         case 460800: brate=B460800; break;
120 #endif
121 #ifdef B921600
122         case 921600: brate=B921600; break;
123 #endif
124     }
125     cfsetispeed(&toptions, brate);
126     cfsetospeed(&toptions, brate);
127 
128     // 8N1
129     toptions.c_cflag &= ~PARENB;
130     toptions.c_cflag &= ~CSTOPB;
131     toptions.c_cflag &= ~CSIZE;
132     toptions.c_cflag |= CS8;
133 
134     if (hci_uart_config->flowcontrol) {
135         // with flow control
136         toptions.c_cflag |= CRTSCTS;
137     } else {
138         // no flow control
139         toptions.c_cflag &= ~CRTSCTS;
140     }
141 
142     toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
143     toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
144 
145     toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
146     toptions.c_oflag &= ~OPOST; // make raw
147 
148     // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
149     toptions.c_cc[VMIN]  = 1;
150     toptions.c_cc[VTIME] = 0;
151 
152     if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
153         perror("init_serialport: Couldn't set term attributes");
154         return -1;
155     }
156 
157     // set up data_source
158     hci_transport_h4->ds = malloc(sizeof(data_source_t));
159     if (!hci_transport_h4->ds) return -1;
160     hci_transport_h4->uart_fd = fd;
161 
162 #ifdef USE_HCI_READER_THREAD
163     // init synchronization tools
164     pthread_mutex_init(&hci_transport_h4->mutex, NULL);
165     pthread_cond_init(&hci_transport_h4->cond, NULL);
166 
167 	// create pipe
168 	pipe(hci_transport_h4->pipe_fds);
169 
170 	// create reader thread
171 	pthread_t hci_reader_thread;
172 	pthread_create(&hci_reader_thread, NULL, &h4_reader, NULL);
173 
174     hci_transport_h4->ds->fd = hci_transport_h4->pipe_fds[0];
175     hci_transport_h4->ds->process = h4_reader_process;
176 #else
177     hci_transport_h4->ds->fd = fd;
178     hci_transport_h4->ds->process = h4_process;
179 #endif
180     run_loop_add_data_source(hci_transport_h4->ds);
181 
182     // init state machine
183     bytes_to_read = 1;
184     h4_state = H4_W4_PACKET_TYPE;
185     read_pos = 0;
186 
187     return 0;
188 }
189 
190 static int    h4_close(){
191     // first remove run loop handler
192 	run_loop_remove_data_source(hci_transport_h4->ds);
193 
194     // close device
195     close(hci_transport_h4->ds->fd);
196     free(hci_transport_h4->ds);
197 
198     // free struct
199     hci_transport_h4->ds = NULL;
200     return 0;
201 }
202 
203 static int h4_send_packet(uint8_t packet_type, uint8_t * packet, int size){
204     if (hci_transport_h4->ds == NULL) return -1;
205     if (hci_transport_h4->uart_fd == 0) return -1;
206     hci_dump_packet( (uint8_t) packet_type, 0, packet, size);
207     write(hci_transport_h4->uart_fd, &packet_type, 1);
208     char *data = (char*) packet;
209     while (size > 0) {
210         int bytes_written = write(hci_transport_h4->uart_fd, data, size);
211         if (bytes_written < 0) {
212             usleep(5000);
213             continue;
214         }
215         data += bytes_written;
216         size -= bytes_written;
217     }
218     return 0;
219 }
220 
221 static void   h4_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
222     packet_handler = handler;
223 }
224 
225 static void   h4_deliver_packet(){
226     if (read_pos < 3) return; // sanity check
227     hci_dump_packet( hci_packet[0], 1, &hci_packet[1], read_pos-1);
228     packet_handler(hci_packet[0], &hci_packet[1], read_pos-1);
229 
230     h4_state = H4_W4_PACKET_TYPE;
231     read_pos = 0;
232     bytes_to_read = 1;
233 }
234 
235 static void h4_statemachine(){
236     switch (h4_state) {
237 
238         case H4_W4_PACKET_TYPE:
239             if (hci_packet[0] == HCI_EVENT_PACKET){
240                 bytes_to_read = HCI_EVENT_PKT_HDR;
241                 h4_state = H4_W4_EVENT_HEADER;
242             } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){
243                 bytes_to_read = HCI_ACL_DATA_PKT_HDR;
244                 h4_state = H4_W4_ACL_HEADER;
245             } else {
246                 fprintf(stderr, "h4_process: invalid packet type 0x%02x\n", hci_packet[0]);
247                 read_pos = 0;
248                 bytes_to_read = 1;
249             }
250             break;
251 
252         case H4_W4_EVENT_HEADER:
253             bytes_to_read = hci_packet[2];
254             h4_state = H4_W4_PAYLOAD;
255             break;
256 
257         case H4_W4_ACL_HEADER:
258             bytes_to_read = READ_BT_16( hci_packet, 3);
259             h4_state = H4_W4_PAYLOAD;
260             break;
261 
262         case H4_W4_PAYLOAD:
263 #ifdef USE_HCI_READER_THREAD
264             h4_state = H4_W4_PICKUP;
265 #else
266             h4_deliver_packet();
267 #endif
268             break;
269     }
270 }
271 
272 static int    h4_process(struct data_source *ds) {
273     if (hci_transport_h4->uart_fd == 0) return -1;
274 
275     // read up to bytes_to_read data in
276     int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read);
277     if (bytes_read < 0) {
278         return bytes_read;
279     }
280     bytes_to_read -= bytes_read;
281     read_pos      += bytes_read;
282     if (bytes_to_read > 0) {
283         return 0;
284     }
285 
286     h4_statemachine();
287     return 0;
288 }
289 
290 static int    h4_reader_process(struct data_source *ds) {
291     // get token
292     char token;
293     read(hci_transport_h4->pipe_fds[0], &token, 1);
294 
295     // hci_reader received complete packet, just pick it up
296     h4_deliver_packet();
297 
298     // un-block reader
299     pthread_mutex_lock(&hci_transport_h4->mutex);
300     pthread_cond_signal(&hci_transport_h4->cond);
301     pthread_mutex_unlock(&hci_transport_h4->mutex);
302     return 0;
303 }
304 
305 #ifdef USE_HCI_READER_THREAD
306 static void *h4_reader(void *context){
307 	while(1){
308         // read up to bytes_to_read data in
309         int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read);
310         // error
311         if (bytes_read < 0) {
312             h4_state = H4_W4_PACKET_TYPE;
313             read_pos = 0;
314             bytes_to_read = 1;
315             continue;
316         }
317 
318         bytes_to_read -= bytes_read;
319         read_pos      += bytes_read;
320 
321         if (bytes_to_read > 0) continue;
322 
323         h4_statemachine();
324 
325         if (h4_state != H4_W4_PICKUP) continue;
326 
327 		// notify main thread
328         char data = 'h';
329 		write(hci_transport_h4->pipe_fds[1], &data, 1);
330 
331 		// wait for response
332 		pthread_mutex_lock(&hci_transport_h4->mutex);
333 		pthread_cond_wait(&hci_transport_h4->cond,&hci_transport_h4->mutex);
334 		pthread_mutex_unlock(&hci_transport_h4->mutex);
335 	}
336 }
337 #endif
338 
339 static const char * h4_get_transport_name(){
340     return "H4";
341 }
342 
343 static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
344 }
345 
346 // get h4 singleton
347 hci_transport_t * hci_transport_h4_instance() {
348     if (hci_transport_h4 == NULL) {
349         hci_transport_h4 = malloc( sizeof(hci_transport_h4_t));
350         hci_transport_h4->ds                                      = NULL;
351         hci_transport_h4->transport.open                          = h4_open;
352         hci_transport_h4->transport.close                         = h4_close;
353         hci_transport_h4->transport.send_packet                   = h4_send_packet;
354         hci_transport_h4->transport.register_packet_handler       = h4_register_packet_handler;
355         hci_transport_h4->transport.get_transport_name            = h4_get_transport_name;
356     }
357     return (hci_transport_t *) hci_transport_h4;
358 }
359