xref: /btstack/src/hci_transport_h4.c (revision f109cc1b607ced5d69f67360237aedeb41fc19c3)
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 
16 typedef enum {
17     H4_W4_PACKET_TYPE,
18     H4_W4_EVENT_HEADER,
19     H4_W4_EVENT_PAYLOAD,
20     H4_W4_ACL_HEADER,
21     H4_W4_ACL_PAYLOAD
22 } H4_STATE;
23 
24 static void dummy_handler(uint8_t *packet, int size);
25 static    hci_uart_config_t *hci_uart_config;
26 
27 static  int fd;
28 static  void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler;
29 static  void (*acl_packet_handler)  (uint8_t *packet, int size) = dummy_handler;
30 
31 // packet reader state machine
32 static  H4_STATE h4_state;
33 static int bytes_to_read;
34 static int read_pos;
35 // static uint8_t hci_event_buffer[255+2]; // maximal payload + 2 bytes header
36 static uint8_t hci_packet[400]; // bigger than largest packet
37 
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     return 0;
111 }
112 
113 static int    h4_send_cmd_packet(uint8_t *packet, int size){
114     printf("CMD: ");
115     hexdump(packet, size);
116 
117     char *data = (char*) packet;
118     char packet_type = HCI_COMMAND_DATA_PACKET;
119     write(fd, &packet_type, 1);
120     while (size > 0) {
121         int bytes_written = write(fd, data, size);
122         if (bytes_written < 0) {
123             return bytes_written;
124         }
125         data += bytes_written;
126         size -= bytes_written;
127     }
128     return 0;
129 }
130 
131 static int    h4_send_acl_packet(uint8_t *packet, int size){
132     printf("ACL> ");
133     hexdump(packet, size);
134 
135     char *data = (char*) packet;
136     char packet_type = HCI_ACL_DATA_PACKET;
137     write(fd, &packet_type, 1);
138     while (size > 0) {
139         int bytes_written = write(fd, data, size);
140         if (bytes_written < 0) {
141             return bytes_written;
142         }
143         data += bytes_written;
144         size -= bytes_written;
145     }
146     return 0;
147 }
148 
149 static void   h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
150     event_packet_handler = handler;
151 }
152 
153 static void   h4_register_acl_packet_handler  (void (*handler)(uint8_t *packet, int size)){
154     acl_packet_handler = handler;
155 }
156 
157 static int    h4_get_fd() {
158     return fd;
159 }
160 
161 static int    h4_handle_data() {
162     // read up to bytes_to_read data in
163     int bytes_read = read(fd, &hci_packet[read_pos], bytes_to_read);
164     if (bytes_read < 0) {
165         return bytes_read;
166     }
167     // printf("Bytes read: %u\n", bytes_read);
168     bytes_to_read -= bytes_read;
169     read_pos      += bytes_read;
170     if (bytes_to_read > 0) {
171         return 0;
172     }
173 
174     // act
175     switch (h4_state) {
176         case H4_W4_PACKET_TYPE:
177             if (hci_packet[0] == HCI_EVENT_PACKET){
178                 read_pos = 0;
179                 bytes_to_read = HCI_EVENT_PKT_HDR;
180                 h4_state = H4_W4_EVENT_HEADER;
181             } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){
182                 read_pos = 0;
183                 bytes_to_read = HCI_ACL_DATA_PKT_HDR;
184                 h4_state = H4_W4_ACL_HEADER;
185             } else {
186             }
187             break;
188         case H4_W4_EVENT_HEADER:
189             bytes_to_read = hci_packet[1];
190             h4_state = H4_W4_EVENT_PAYLOAD;
191             break;
192         case H4_W4_EVENT_PAYLOAD:
193             printf("EVT: ");
194             hexdump(hci_packet, read_pos);
195             event_packet_handler(hci_packet, read_pos);
196             h4_state = H4_W4_PACKET_TYPE;
197             read_pos = 0;
198             bytes_to_read = 1;
199             break;
200         case H4_W4_ACL_HEADER:
201             bytes_to_read = READ_BT_16( hci_packet, 2);
202             h4_state = H4_W4_ACL_PAYLOAD;
203             break;
204         case H4_W4_ACL_PAYLOAD:
205             printf("<ACL ");
206             hexdump(hci_packet, read_pos);
207             acl_packet_handler(hci_packet, read_pos);
208             h4_state = H4_W4_PACKET_TYPE;
209             read_pos = 0;
210             bytes_to_read = 1;
211             break;
212     }
213     return 0;
214 }
215 
216 static const char * h4_get_transport_name(){
217     return "H4";
218 }
219 
220 static void dummy_handler(uint8_t *packet, int size){
221 }
222 
223 // single instance
224 hci_transport_t hci_transport_h4 = {
225     h4_open,
226     h4_close,
227     h4_send_cmd_packet,
228     h4_send_acl_packet,
229     h4_register_event_packet_handler,
230     h4_register_acl_packet_handler,
231     h4_get_fd,
232     h4_handle_data,
233     h4_get_transport_name
234 };
235