xref: /btstack/src/hci_transport_h4.c (revision d96599227022dac90cc65c19dee07fb5e9d833af)
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 static void dummy_handler(uint8_t *packet, int size);
26 static    hci_uart_config_t *hci_uart_config;
27 
28 static  int fd;
29 static  void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler;
30 static  void (*acl_packet_handler)  (uint8_t *packet, int size) = dummy_handler;
31 
32 // packet reader state machine
33 static  H4_STATE h4_state;
34 static int bytes_to_read;
35 static int read_pos;
36 // static uint8_t hci_event_buffer[255+2]; // maximal payload + 2 bytes header
37 static uint8_t hci_packet[400]; // bigger than largest packet
38 
39 
40 // prototypes
41 static int    h4_open(void *transport_config){
42     hci_uart_config = (hci_uart_config_t*) transport_config;
43     struct termios toptions;
44     fd = open(hci_uart_config->device_name, O_RDWR | O_NOCTTY | O_NDELAY);
45     if (fd == -1)  {
46         perror("init_serialport: Unable to open port ");
47         perror(hci_uart_config->device_name);
48         return -1;
49     }
50 
51     if (tcgetattr(fd, &toptions) < 0) {
52         perror("init_serialport: Couldn't get term attributes");
53         return -1;
54     }
55     speed_t brate = hci_uart_config->baudrate; // let you override switch below if needed
56     switch(hci_uart_config->baudrate) {
57         case 57600:  brate=B57600;  break;
58         case 115200: brate=B115200; break;
59 #ifdef B230400
60         case 230400: brate=B230400; break;
61 #endif
62 #ifdef B460800
63         case 460800: brate=B460800; break;
64 #endif
65 #ifdef B921600
66         case 921600: brate=B921600; break;
67 #endif
68     }
69     cfsetispeed(&toptions, brate);
70     cfsetospeed(&toptions, brate);
71 
72     // 8N1
73     toptions.c_cflag &= ~PARENB;
74     toptions.c_cflag &= ~CSTOPB;
75     toptions.c_cflag &= ~CSIZE;
76     toptions.c_cflag |= CS8;
77 
78     if (hci_uart_config->flowcontrol) {
79         // with flow control
80         toptions.c_cflag |= CRTSCTS;
81     } else {
82         // no flow control
83         toptions.c_cflag &= ~CRTSCTS;
84     }
85 
86     toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
87     toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
88 
89     toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
90     toptions.c_oflag &= ~OPOST; // make raw
91 
92     // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
93     toptions.c_cc[VMIN]  = 1;
94     toptions.c_cc[VTIME] = 0;
95 
96     if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
97         perror("init_serialport: Couldn't set term attributes");
98         return -1;
99     }
100 
101     // init state machine
102     bytes_to_read = 1;
103     h4_state = H4_W4_PACKET_TYPE;
104     read_pos = 0;
105 
106     return 0;
107 }
108 
109 static int    h4_close(){
110     close(fd);
111     return 0;
112 }
113 
114 static int    h4_send_cmd_packet(uint8_t *packet, int size){
115     printf("CMD: ");
116     hexdump(packet, size);
117 
118     char *data = (char*) packet;
119     char packet_type = HCI_COMMAND_DATA_PACKET;
120 
121     hci_dump_packet( (uint8_t) packet_type, 0, packet, size);
122 
123     write(fd, &packet_type, 1);
124     while (size > 0) {
125         int bytes_written = write(fd, data, size);
126         if (bytes_written < 0) {
127             return bytes_written;
128         }
129         data += bytes_written;
130         size -= bytes_written;
131     }
132     return 0;
133 }
134 
135 static int    h4_send_acl_packet(uint8_t *packet, int size){
136     printf("ACL> ");
137     hexdump(packet, size);
138 
139     char *data = (char*) packet;
140     char packet_type = HCI_ACL_DATA_PACKET;
141 
142     hci_dump_packet( (uint8_t) packet_type, 0, packet, size);
143 
144     write(fd, &packet_type, 1);
145     while (size > 0) {
146         int bytes_written = write(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 void   h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
157     event_packet_handler = handler;
158 }
159 
160 static void   h4_register_acl_packet_handler  (void (*handler)(uint8_t *packet, int size)){
161     acl_packet_handler = handler;
162 }
163 
164 static int    h4_get_fd() {
165     return fd;
166 }
167 
168 static int    h4_handle_data() {
169     // read up to bytes_to_read data in
170     int bytes_read = read(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             printf("EVT: ");
201             hexdump(hci_packet, read_pos);
202 
203             hci_dump_packet( HCI_EVENT_PACKET, 1, hci_packet, read_pos);
204 
205             event_packet_handler(hci_packet, read_pos);
206             h4_state = H4_W4_PACKET_TYPE;
207             read_pos = 0;
208             bytes_to_read = 1;
209             break;
210         case H4_W4_ACL_HEADER:
211             bytes_to_read = READ_BT_16( hci_packet, 2);
212             h4_state = H4_W4_ACL_PAYLOAD;
213             break;
214         case H4_W4_ACL_PAYLOAD:
215             printf("<ACL ");
216             hexdump(hci_packet, read_pos);
217 
218             hci_dump_packet( HCI_ACL_DATA_PACKET, 1, hci_packet, read_pos);
219 
220             acl_packet_handler(hci_packet, read_pos);
221             h4_state = H4_W4_PACKET_TYPE;
222             read_pos = 0;
223             bytes_to_read = 1;
224             break;
225     }
226     return 0;
227 }
228 
229 static const char * h4_get_transport_name(){
230     return "H4";
231 }
232 
233 static void dummy_handler(uint8_t *packet, int size){
234 }
235 
236 // single instance
237 hci_transport_t hci_transport_h4 = {
238     h4_open,
239     h4_close,
240     h4_send_cmd_packet,
241     h4_send_acl_packet,
242     h4_register_event_packet_handler,
243     h4_register_acl_packet_handler,
244     h4_get_fd,
245     h4_handle_data,
246     h4_get_transport_name
247 };
248