xref: /btstack/src/hci_transport_h4.c (revision 7382b6a1c54c4d4d275307896b8ecc39c1672440)
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 
197     // free struct
198     free(hci_transport_h4->ds);
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     char *data = (char*) packet;
208     int bytes_written = write(hci_transport_h4->uart_fd, &packet_type, 1);
209     while (bytes_written < 1) {
210         usleep(5000);
211         bytes_written = write(hci_transport_h4->uart_fd, &packet_type, 1);
212     };
213     while (size > 0) {
214         int bytes_written = write(hci_transport_h4->uart_fd, data, size);
215         if (bytes_written < 0) {
216             usleep(5000);
217             continue;
218         }
219         data += bytes_written;
220         size -= bytes_written;
221     }
222     return 0;
223 }
224 
225 static void   h4_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
226     packet_handler = handler;
227 }
228 
229 static void   h4_deliver_packet(){
230     if (read_pos < 3) return; // sanity check
231     hci_dump_packet( hci_packet[0], 1, &hci_packet[1], read_pos-1);
232     packet_handler(hci_packet[0], &hci_packet[1], read_pos-1);
233 
234     h4_state = H4_W4_PACKET_TYPE;
235     read_pos = 0;
236     bytes_to_read = 1;
237 }
238 
239 static void h4_statemachine(){
240     switch (h4_state) {
241 
242         case H4_W4_PACKET_TYPE:
243             if (hci_packet[0] == HCI_EVENT_PACKET){
244                 bytes_to_read = HCI_EVENT_PKT_HDR;
245                 h4_state = H4_W4_EVENT_HEADER;
246             } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){
247                 bytes_to_read = HCI_ACL_DATA_PKT_HDR;
248                 h4_state = H4_W4_ACL_HEADER;
249             } else {
250                 fprintf(stderr, "h4_process: invalid packet type 0x%02x\n", hci_packet[0]);
251                 read_pos = 0;
252                 bytes_to_read = 1;
253             }
254             break;
255 
256         case H4_W4_EVENT_HEADER:
257             bytes_to_read = hci_packet[2];
258             h4_state = H4_W4_PAYLOAD;
259             break;
260 
261         case H4_W4_ACL_HEADER:
262             bytes_to_read = READ_BT_16( hci_packet, 3);
263             h4_state = H4_W4_PAYLOAD;
264             break;
265 
266         case H4_W4_PAYLOAD:
267 #ifdef USE_HCI_READER_THREAD
268             h4_state = H4_W4_PICKUP;
269 #else
270             h4_deliver_packet();
271 #endif
272             break;
273     }
274 }
275 
276 static int    h4_process(struct data_source *ds) {
277     if (hci_transport_h4->uart_fd == 0) return -1;
278 
279     // read up to bytes_to_read data in
280     int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read);
281     if (bytes_read < 0) {
282         return bytes_read;
283     }
284     bytes_to_read -= bytes_read;
285     read_pos      += bytes_read;
286     if (bytes_to_read > 0) {
287         return 0;
288     }
289 
290     h4_statemachine();
291     return 0;
292 }
293 
294 #ifdef USE_HCI_READER_THREAD
295 static int h4_reader_process(struct data_source *ds) {
296     // get token
297     char token;
298     read(hci_transport_h4->pipe_fds[0], &token, 1);
299 
300     // hci_reader received complete packet, just pick it up
301     h4_deliver_packet();
302 
303     // un-block reader
304     pthread_mutex_lock(&hci_transport_h4->mutex);
305     pthread_cond_signal(&hci_transport_h4->cond);
306     pthread_mutex_unlock(&hci_transport_h4->mutex);
307     return 0;
308 }
309 
310 static void *h4_reader(void *context){
311 	while(1){
312         // read up to bytes_to_read data in
313         int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read);
314         // error
315         if (bytes_read < 0) {
316             h4_state = H4_W4_PACKET_TYPE;
317             read_pos = 0;
318             bytes_to_read = 1;
319             continue;
320         }
321 
322         bytes_to_read -= bytes_read;
323         read_pos      += bytes_read;
324 
325         if (bytes_to_read > 0) continue;
326 
327         h4_statemachine();
328 
329         if (h4_state != H4_W4_PICKUP) continue;
330 
331 		// notify main thread
332         char data = 'h';
333 		write(hci_transport_h4->pipe_fds[1], &data, 1);
334 
335 		// wait for response
336 		pthread_mutex_lock(&hci_transport_h4->mutex);
337 		pthread_cond_wait(&hci_transport_h4->cond,&hci_transport_h4->mutex);
338 		pthread_mutex_unlock(&hci_transport_h4->mutex);
339 	}
340 }
341 #endif
342 
343 static const char * h4_get_transport_name(){
344     return "H4";
345 }
346 
347 static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
348 }
349 
350 // get h4 singleton
351 hci_transport_t * hci_transport_h4_instance() {
352     if (hci_transport_h4 == NULL) {
353         hci_transport_h4 = malloc( sizeof(hci_transport_h4_t));
354         hci_transport_h4->ds                                      = NULL;
355         hci_transport_h4->transport.open                          = h4_open;
356         hci_transport_h4->transport.close                         = h4_close;
357         hci_transport_h4->transport.send_packet                   = h4_send_packet;
358         hci_transport_h4->transport.register_packet_handler       = h4_register_packet_handler;
359         hci_transport_h4->transport.get_transport_name            = h4_get_transport_name;
360     }
361     return (hci_transport_t *) hci_transport_h4;
362 }
363