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