xref: /btstack/src/hci_transport_h4.c (revision ea6387df266da0720d97951c099ef33e618dbf23)
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         return -1;
47     }
48 
49     if (tcgetattr(fd, &toptions) < 0) {
50         perror("init_serialport: Couldn't get term attributes");
51         return -1;
52     }
53     speed_t brate = hci_uart_config->baudrate; // let you override switch below if needed
54     switch(hci_uart_config->baudrate) {
55         case 57600:  brate=B57600;  break;
56         case 115200: brate=B115200; break;
57     }
58     cfsetispeed(&toptions, brate);
59     cfsetospeed(&toptions, brate);
60 
61     // 8N1
62     toptions.c_cflag &= ~PARENB;
63     toptions.c_cflag &= ~CSTOPB;
64     toptions.c_cflag &= ~CSIZE;
65     toptions.c_cflag |= CS8;
66 
67     if (hci_uart_config->flowcontrol) {
68         // with flow control
69         toptions.c_cflag |= CRTSCTS;
70     } else {
71         // no flow control
72         toptions.c_cflag &= ~CRTSCTS;
73     }
74 
75     toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
76     toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
77 
78     toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
79     toptions.c_oflag &= ~OPOST; // make raw
80 
81     // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
82     toptions.c_cc[VMIN]  = 1;
83     toptions.c_cc[VTIME] = 0;
84 
85     if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
86         perror("init_serialport: Couldn't set term attributes");
87         return -1;
88     }
89 
90     // init state machine
91     bytes_to_read = 1;
92     h4_state = H4_W4_PACKET_TYPE;
93     read_pos = 0;
94 
95     return 0;
96 }
97 
98 static int    h4_close(){
99     return 0;
100 }
101 
102 static int    h4_send_cmd_packet(uint8_t *packet, int size){
103     printf("CMD: ");
104     hexdump(packet, size);
105 
106     char *data = (char*) packet;
107     char packet_type = HCI_COMMAND_DATA_PACKET;
108     write(fd, &packet_type, 1);
109     while (size > 0) {
110         int bytes_written = write(fd, data, size);
111         if (bytes_written < 0) {
112             return bytes_written;
113         }
114         data += bytes_written;
115         size -= bytes_written;
116     }
117     return 0;
118 }
119 
120 static int    h4_send_acl_packet(uint8_t *packet, int size){
121     printf("ACL> ");
122     hexdump(packet, size);
123 
124     char *data = (char*) packet;
125     char packet_type = HCI_ACL_DATA_PACKET;
126     write(fd, &packet_type, 1);
127     while (size > 0) {
128         int bytes_written = write(fd, data, size);
129         if (bytes_written < 0) {
130             return bytes_written;
131         }
132         data += bytes_written;
133         size -= bytes_written;
134     }
135     return 0;
136 }
137 
138 static void   h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
139     event_packet_handler = handler;
140 }
141 
142 static void   h4_register_acl_packet_handler  (void (*handler)(uint8_t *packet, int size)){
143     acl_packet_handler = handler;
144 }
145 
146 static int    h4_get_fd() {
147     return fd;
148 }
149 
150 static int    h4_handle_data() {
151     // read up to bytes_to_read data in
152     int bytes_read = read(fd, &hci_packet[read_pos], bytes_to_read);
153     if (bytes_read < 0) {
154         return bytes_read;
155     }
156     // printf("Bytes read: %u\n", bytes_read);
157     bytes_to_read -= bytes_read;
158     read_pos      += bytes_read;
159     if (bytes_to_read > 0) {
160         return 0;
161     }
162 
163     // act
164     switch (h4_state) {
165         case H4_W4_PACKET_TYPE:
166             if (hci_packet[0] == HCI_EVENT_PACKET){
167                 read_pos = 0;
168                 bytes_to_read = HCI_EVENT_PKT_HDR;
169                 h4_state = H4_W4_EVENT_HEADER;
170             } else if (hci_packet[0] == HCI_ACL_DATA_PACKET){
171                 read_pos = 0;
172                 bytes_to_read = HCI_ACL_DATA_PKT_HDR;
173                 h4_state = H4_W4_ACL_HEADER;
174             } else {
175             }
176             break;
177         case H4_W4_EVENT_HEADER:
178             bytes_to_read = hci_packet[1];
179             h4_state = H4_W4_EVENT_PAYLOAD;
180             break;
181         case H4_W4_EVENT_PAYLOAD:
182             printf("EVT: ");
183             hexdump(hci_packet, read_pos);
184             event_packet_handler(hci_packet, read_pos);
185             h4_state = H4_W4_PACKET_TYPE;
186             read_pos = 0;
187             bytes_to_read = 1;
188             break;
189         case H4_W4_ACL_HEADER:
190             bytes_to_read = READ_BT_16( hci_packet, 2);
191             h4_state = H4_W4_ACL_PAYLOAD;
192             break;
193         case H4_W4_ACL_PAYLOAD:
194             printf("<ACL ");
195             hexdump(hci_packet, read_pos);
196             acl_packet_handler(hci_packet, read_pos);
197             h4_state = H4_W4_PACKET_TYPE;
198             read_pos = 0;
199             bytes_to_read = 1;
200             break;
201     }
202     return 0;
203 }
204 
205 static const char * h4_get_transport_name(){
206     return "H4";
207 }
208 
209 static void dummy_handler(uint8_t *packet, int size){
210 }
211 
212 // single instance
213 hci_transport_t hci_h4_transport = {
214     h4_open,
215     h4_close,
216     h4_send_cmd_packet,
217     h4_send_acl_packet,
218     h4_register_event_packet_handler,
219     h4_register_acl_packet_handler,
220     h4_get_fd,
221     h4_handle_data,
222     h4_get_transport_name
223 };
224