xref: /btstack/src/hci_transport_h4.c (revision c095e79e4dd91872d161df5e7e8d5888961bac81)
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     hci_dump_close();
111     close(fd);
112     return 0;
113 }
114 
115 static int    h4_send_cmd_packet(uint8_t *packet, int size){
116     printf("CMD: ");
117     hexdump(packet, size);
118 
119     char *data = (char*) packet;
120     char packet_type = HCI_COMMAND_DATA_PACKET;
121 
122     hci_dump_packet( (uint8_t) packet_type, 0, packet, size);
123 
124     write(fd, &packet_type, 1);
125     while (size > 0) {
126         int bytes_written = write(fd, data, size);
127         if (bytes_written < 0) {
128             return bytes_written;
129         }
130         data += bytes_written;
131         size -= bytes_written;
132     }
133     return 0;
134 }
135 
136 static int    h4_send_acl_packet(uint8_t *packet, int size){
137     printf("ACL> ");
138     hexdump(packet, size);
139 
140     char *data = (char*) packet;
141     char packet_type = HCI_ACL_DATA_PACKET;
142 
143     hci_dump_packet( (uint8_t) packet_type, 0, packet, size);
144 
145     write(fd, &packet_type, 1);
146     while (size > 0) {
147         int bytes_written = write(fd, data, size);
148         if (bytes_written < 0) {
149             return bytes_written;
150         }
151         data += bytes_written;
152         size -= bytes_written;
153     }
154     return 0;
155 }
156 
157 static void   h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
158     event_packet_handler = handler;
159 }
160 
161 static void   h4_register_acl_packet_handler  (void (*handler)(uint8_t *packet, int size)){
162     acl_packet_handler = handler;
163 }
164 
165 static int    h4_get_fd() {
166     return fd;
167 }
168 
169 static int    h4_handle_data() {
170     // read up to bytes_to_read data in
171     int bytes_read = read(fd, &hci_packet[read_pos], bytes_to_read);
172     if (bytes_read < 0) {
173         return bytes_read;
174     }
175     // printf("Bytes read: %u\n", bytes_read);
176     bytes_to_read -= bytes_read;
177     read_pos      += bytes_read;
178     if (bytes_to_read > 0) {
179         return 0;
180     }
181 
182     // act
183     switch (h4_state) {
184         case H4_W4_PACKET_TYPE:
185             if (hci_packet[0] == HCI_EVENT_PACKET){
186                 read_pos = 0;
187                 bytes_to_read = HCI_EVENT_PKT_HDR;
188                 h4_state = H4_W4_EVENT_HEADER;
189             } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){
190                 read_pos = 0;
191                 bytes_to_read = HCI_ACL_DATA_PKT_HDR;
192                 h4_state = H4_W4_ACL_HEADER;
193             } else {
194             }
195             break;
196         case H4_W4_EVENT_HEADER:
197             bytes_to_read = hci_packet[1];
198             h4_state = H4_W4_EVENT_PAYLOAD;
199             break;
200         case H4_W4_EVENT_PAYLOAD:
201             printf("EVT: ");
202             hexdump(hci_packet, read_pos);
203 
204             hci_dump_packet( HCI_EVENT_PACKET, 1, hci_packet, read_pos);
205 
206             event_packet_handler(hci_packet, read_pos);
207             h4_state = H4_W4_PACKET_TYPE;
208             read_pos = 0;
209             bytes_to_read = 1;
210             break;
211         case H4_W4_ACL_HEADER:
212             bytes_to_read = READ_BT_16( hci_packet, 2);
213             h4_state = H4_W4_ACL_PAYLOAD;
214             break;
215         case H4_W4_ACL_PAYLOAD:
216             printf("<ACL ");
217             hexdump(hci_packet, read_pos);
218 
219             hci_dump_packet( HCI_ACL_DATA_PACKET, 1, hci_packet, read_pos);
220 
221             acl_packet_handler(hci_packet, read_pos);
222             h4_state = H4_W4_PACKET_TYPE;
223             read_pos = 0;
224             bytes_to_read = 1;
225             break;
226     }
227     return 0;
228 }
229 
230 static const char * h4_get_transport_name(){
231     return "H4";
232 }
233 
234 static void dummy_handler(uint8_t *packet, int size){
235 }
236 
237 // single instance
238 hci_transport_t hci_transport_h4 = {
239     h4_open,
240     h4_close,
241     h4_send_cmd_packet,
242     h4_send_acl_packet,
243     h4_register_event_packet_handler,
244     h4_register_acl_packet_handler,
245     h4_get_fd,
246     h4_handle_data,
247     h4_get_transport_name
248 };
249