xref: /btstack/src/hci_transport_h4.c (revision 22909952ea76c45a8db20409374b80e7e0204e4c)
1 /*
2  *  hci_h4_transport.c
3  *
4  *  Created by Matthias Ringwald on 4/29/09.
5  *
6  */
7 #include <termios.h>  /* POSIX terminal control definitions */
8 #include <fcntl.h>    /* File control definitions */
9 #include <unistd.h>   /* UNIX standard function definitions */
10 #include <stdio.h>
11 
12 #include "hci.h"
13 #include "hci_transport_h4.h"
14 
15 typedef enum {
16     H4_W4_PACKET_TYPE,
17     H4_W4_EVENT_HEADER,
18     H4_W4_EVENT_PAYLOAD,
19     H4_W4_ACL_HEADER,
20     H4_W4_ACL_PAYLOAD
21 } H4_STATE;
22 
23 static void dummy_handler(uint8_t *packet, int size);
24 static    hci_uart_config_t *hci_uart_config;
25 
26 static  int fd;
27 static  void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler;
28 static  void (*acl_packet_handler)  (uint8_t *packet, int size) = dummy_handler;
29 
30 // packet reader state machine
31 static  H4_STATE h4_state;
32 static int bytes_to_read;
33 static int read_pos;
34 // static uint8_t hci_event_buffer[255+2]; // maximal payload + 2 bytes header
35 static uint8_t hci_packet[400]; // bigger than largest packet
36 
37 
38 
39 // prototypes
40 static int    h4_open(void *transport_config){
41     hci_uart_config = (hci_uart_config_t*) transport_config;
42     struct termios toptions;
43     fd = open(hci_uart_config->device_name, O_RDWR | O_NOCTTY | O_NDELAY);
44     if (fd == -1)  {
45         perror("init_serialport: Unable to open port ");
46         perror(hci_uart_config->device_name);
47         return -1;
48     }
49 
50     if (tcgetattr(fd, &toptions) < 0) {
51         perror("init_serialport: Couldn't get term attributes");
52         return -1;
53     }
54     speed_t brate = hci_uart_config->baudrate; // let you override switch below if needed
55     switch(hci_uart_config->baudrate) {
56         case 57600:  brate=B57600;  break;
57         case 115200: brate=B115200; break;
58     }
59     cfsetispeed(&toptions, brate);
60     cfsetospeed(&toptions, brate);
61 
62     // 8N1
63     toptions.c_cflag &= ~PARENB;
64     toptions.c_cflag &= ~CSTOPB;
65     toptions.c_cflag &= ~CSIZE;
66     toptions.c_cflag |= CS8;
67 
68     if (hci_uart_config->flowcontrol) {
69         // with flow control
70         toptions.c_cflag |= CRTSCTS;
71     } else {
72         // no flow control
73         toptions.c_cflag &= ~CRTSCTS;
74     }
75 
76     toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
77     toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
78 
79     toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
80     toptions.c_oflag &= ~OPOST; // make raw
81 
82     // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
83     toptions.c_cc[VMIN]  = 1;
84     toptions.c_cc[VTIME] = 0;
85 
86     if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
87         perror("init_serialport: Couldn't set term attributes");
88         return -1;
89     }
90 
91     // init state machine
92     bytes_to_read = 1;
93     h4_state = H4_W4_PACKET_TYPE;
94     read_pos = 0;
95 
96     return 0;
97 }
98 
99 static int    h4_close(){
100     return 0;
101 }
102 
103 static int    h4_send_cmd_packet(uint8_t *packet, int size){
104     printf("CMD: ");
105     hexdump(packet, size);
106 
107     char *data = (char*) packet;
108     char packet_type = HCI_COMMAND_DATA_PACKET;
109     write(fd, &packet_type, 1);
110     while (size > 0) {
111         int bytes_written = write(fd, data, size);
112         if (bytes_written < 0) {
113             return bytes_written;
114         }
115         data += bytes_written;
116         size -= bytes_written;
117     }
118     return 0;
119 }
120 
121 static int    h4_send_acl_packet(uint8_t *packet, int size){
122     printf("ACL> ");
123     hexdump(packet, size);
124 
125     char *data = (char*) packet;
126     char packet_type = HCI_ACL_DATA_PACKET;
127     write(fd, &packet_type, 1);
128     while (size > 0) {
129         int bytes_written = write(fd, data, size);
130         if (bytes_written < 0) {
131             return bytes_written;
132         }
133         data += bytes_written;
134         size -= bytes_written;
135     }
136     return 0;
137 }
138 
139 static void   h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
140     event_packet_handler = handler;
141 }
142 
143 static void   h4_register_acl_packet_handler  (void (*handler)(uint8_t *packet, int size)){
144     acl_packet_handler = handler;
145 }
146 
147 static int    h4_get_fd() {
148     return fd;
149 }
150 
151 static int    h4_handle_data() {
152     // read up to bytes_to_read data in
153     int bytes_read = read(fd, &hci_packet[read_pos], bytes_to_read);
154     if (bytes_read < 0) {
155         return bytes_read;
156     }
157     // printf("Bytes read: %u\n", bytes_read);
158     bytes_to_read -= bytes_read;
159     read_pos      += bytes_read;
160     if (bytes_to_read > 0) {
161         return 0;
162     }
163 
164     // act
165     switch (h4_state) {
166         case H4_W4_PACKET_TYPE:
167             if (hci_packet[0] == HCI_EVENT_PACKET){
168                 read_pos = 0;
169                 bytes_to_read = HCI_EVENT_PKT_HDR;
170                 h4_state = H4_W4_EVENT_HEADER;
171             } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){
172                 read_pos = 0;
173                 bytes_to_read = HCI_ACL_DATA_PKT_HDR;
174                 h4_state = H4_W4_ACL_HEADER;
175             } else {
176             }
177             break;
178         case H4_W4_EVENT_HEADER:
179             bytes_to_read = hci_packet[1];
180             h4_state = H4_W4_EVENT_PAYLOAD;
181             break;
182         case H4_W4_EVENT_PAYLOAD:
183             printf("EVT: ");
184             hexdump(hci_packet, read_pos);
185             event_packet_handler(hci_packet, read_pos);
186             h4_state = H4_W4_PACKET_TYPE;
187             read_pos = 0;
188             bytes_to_read = 1;
189             break;
190         case H4_W4_ACL_HEADER:
191             bytes_to_read = READ_BT_16( hci_packet, 2);
192             h4_state = H4_W4_ACL_PAYLOAD;
193             break;
194         case H4_W4_ACL_PAYLOAD:
195             printf("<ACL ");
196             hexdump(hci_packet, read_pos);
197             acl_packet_handler(hci_packet, read_pos);
198             h4_state = H4_W4_PACKET_TYPE;
199             read_pos = 0;
200             bytes_to_read = 1;
201             break;
202     }
203     return 0;
204 }
205 
206 static const char * h4_get_transport_name(){
207     return "H4";
208 }
209 
210 static void dummy_handler(uint8_t *packet, int size){
211 }
212 
213 // single instance
214 hci_transport_t hci_h4_transport = {
215     h4_open,
216     h4_close,
217     h4_send_cmd_packet,
218     h4_send_acl_packet,
219     h4_register_event_packet_handler,
220     h4_register_acl_packet_handler,
221     h4_get_fd,
222     h4_handle_data,
223     h4_get_transport_name
224 };
225