xref: /btstack/src/hci_transport_h4.c (revision 9bf70ccba9fff8d5abe489de210e70c74acb19ee)
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, int ready);
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(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     close(hci_transport_h4->ds->fd);
125     free(hci_transport_h4->ds);
126     hci_transport_h4->ds = NULL;
127     return 0;
128 }
129 
130 static int    h4_send_cmd_packet(uint8_t *packet, int size){
131     if (hci_transport_h4->ds == NULL) return -1;
132     if (hci_transport_h4->ds->fd == 0) return -1;
133     char *data = (char*) packet;
134     char packet_type = HCI_COMMAND_DATA_PACKET;
135 
136     hci_dump_packet( (uint8_t) packet_type, 0, packet, size);
137 
138     write(hci_transport_h4->ds->fd, &packet_type, 1);
139     while (size > 0) {
140         int bytes_written = write(hci_transport_h4->ds->fd, data, size);
141         if (bytes_written < 0) {
142             return bytes_written;
143         }
144         data += bytes_written;
145         size -= bytes_written;
146     }
147     return 0;
148 }
149 
150 static int    h4_send_acl_packet(uint8_t *packet, int size){
151     if (hci_transport_h4->ds->fd == 0) return -1;
152 
153     char *data = (char*) packet;
154     char packet_type = HCI_ACL_DATA_PACKET;
155 
156     hci_dump_packet( (uint8_t) packet_type, 0, packet, size);
157 
158     write(hci_transport_h4->ds->fd, &packet_type, 1);
159     while (size > 0) {
160         int bytes_written = write(hci_transport_h4->ds->fd, data, size);
161         if (bytes_written < 0) {
162             return bytes_written;
163         }
164         data += bytes_written;
165         size -= bytes_written;
166     }
167     return 0;
168 }
169 
170 static void   h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
171     event_packet_handler = handler;
172 }
173 
174 static void   h4_register_acl_packet_handler  (void (*handler)(uint8_t *packet, int size)){
175     acl_packet_handler = handler;
176 }
177 
178 static int    h4_process(struct data_source *ds, int ready) {
179     if (hci_transport_h4->ds->fd == 0) return -1;
180 
181     // read up to bytes_to_read data in
182     int bytes_read = read(hci_transport_h4->ds->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 			hci_dump_packet( HCI_EVENT_PACKET, 1, hci_packet, read_pos);
213             event_packet_handler(hci_packet, read_pos);
214             h4_state = H4_W4_PACKET_TYPE;
215             read_pos = 0;
216             bytes_to_read = 1;
217             break;
218         case H4_W4_ACL_HEADER:
219             bytes_to_read = READ_BT_16( hci_packet, 2);
220             h4_state = H4_W4_ACL_PAYLOAD;
221             break;
222         case H4_W4_ACL_PAYLOAD:
223             hci_dump_packet( HCI_ACL_DATA_PACKET, 1, hci_packet, read_pos);
224 
225             acl_packet_handler(hci_packet, read_pos);
226             h4_state = H4_W4_PACKET_TYPE;
227             read_pos = 0;
228             bytes_to_read = 1;
229             break;
230     }
231     return 0;
232 }
233 
234 static const char * h4_get_transport_name(){
235     return "H4";
236 }
237 
238 static void dummy_handler(uint8_t *packet, int size){
239 }
240 
241 // get h4 singleton
242 hci_transport_t * hci_transport_h4_instance() {
243     if (hci_transport_h4 == NULL) {
244         hci_transport_h4 = malloc( sizeof(hci_transport_h4_t));
245         hci_transport_h4->ds                                      = NULL;
246         hci_transport_h4->transport.open                          = h4_open;
247         hci_transport_h4->transport.close                         = h4_close;
248         hci_transport_h4->transport.send_cmd_packet               = h4_send_cmd_packet;
249         hci_transport_h4->transport.send_acl_packet               = h4_send_acl_packet;
250         hci_transport_h4->transport.register_event_packet_handler = h4_register_event_packet_handler;
251         hci_transport_h4->transport.register_acl_packet_handler   = h4_register_acl_packet_handler;
252         hci_transport_h4->transport.get_transport_name            = h4_get_transport_name;
253     }
254     return hci_transport_h4;
255 }
256