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