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