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