xref: /btstack/src/hci_transport_h4.c (revision 2e36e02a2616d5e5cce87836b31c7cd43786843a)
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_transport_h4.h"
13 
14 typedef enum {
15     H4_W4_PACKET_TYPE,
16     H4_W4_EVENT_HEADER,
17     H4_W4_EVENT_PAYLOAD,
18     H4_W4_ACL_HEADER,
19     H4_W4_ACL_PAYLOAD
20 } H4_STATE;
21 
22 static void dummy_handler(uint8_t *packet, int size);
23 
24 // typedef struct {
25 // static    hci_uart_config_t *config;
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 static  H4_STATE h4_state;
30 static int bytes_to_read;
31 static int read_pos;
32 static uint8_t hci_event_buffer[255+2]; // maximal payload + 2 bytes header
33 // } hci_h4_transport_private;
34 
35 
36 
37 // prototypes
38 static int    h4_open(void *transport_config){
39     hci_uart_config_t * uart_config = (hci_uart_config_t*) transport_config;
40     struct termios toptions;
41     fd = open(uart_config->device_name, O_RDWR | O_NOCTTY | O_NDELAY);
42     if (fd == -1)  {
43         perror("init_serialport: Unable to open port ");
44         return -1;
45     }
46 
47     if (tcgetattr(fd, &toptions) < 0) {
48         perror("init_serialport: Couldn't get term attributes");
49         return -1;
50     }
51     speed_t brate = uart_config->baudrate; // let you override switch below if needed
52     switch(uart_config->baudrate) {
53         case 57600:  brate=B57600;  break;
54         case 115200: brate=B115200; break;
55     }
56     cfsetispeed(&toptions, brate);
57     cfsetospeed(&toptions, brate);
58 
59     // 8N1
60     toptions.c_cflag &= ~PARENB;
61     toptions.c_cflag &= ~CSTOPB;
62     toptions.c_cflag &= ~CSIZE;
63     toptions.c_cflag |= CS8;
64 
65     if (uart_config->flowcontrol) {
66         // with flow control
67         toptions.c_cflag |= CRTSCTS;
68     } else {
69         // no flow control
70         toptions.c_cflag &= ~CRTSCTS;
71     }
72 
73     toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
74     toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
75 
76     toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
77     toptions.c_oflag &= ~OPOST; // make raw
78 
79     // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
80     toptions.c_cc[VMIN]  = 1;
81     toptions.c_cc[VTIME] = 0;
82 
83     if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
84         perror("init_serialport: Couldn't set term attributes");
85         return -1;
86     }
87 
88     // init state machine
89     bytes_to_read = 1;
90     h4_state = H4_W4_PACKET_TYPE;
91     read_pos = 0;
92 
93     return 0;
94 }
95 
96 static int    h4_close(){
97     return 0;
98 }
99 
100 static int    h4_send_cmd_packet(uint8_t *packet, int size){
101     char *data = (char*) packet;
102     char cmd_type = 1;
103     write(fd, &cmd_type, 1);
104     while (size > 0) {
105         int bytes_written = write(fd, data, size);
106         if (bytes_written < 0) {
107             return bytes_written;
108         }
109         data += bytes_written;
110         size -= bytes_written;
111     }
112     return 0;
113 }
114 
115 static int    h4_send_acl_packet(uint8_t *packet, int size){
116     return 0;
117 }
118 
119 static void   h4_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){
120     event_packet_handler = handler;
121 }
122 
123 static void   h4_register_acl_packet_handler  (void (*handler)(uint8_t *packet, int size)){
124     acl_packet_handler = handler;
125 }
126 
127 static int    h4_get_fd() {
128     return fd;
129 }
130 
131 static int    h4_handle_data() {
132     // read up to bytes_to_read data in
133     int bytes_read = read(fd, &hci_event_buffer[read_pos], bytes_to_read);
134     if (bytes_read < 0) {
135         return bytes_read;
136     }
137     // printf("Bytes read: %u\n", bytes_read);
138     bytes_to_read -= bytes_read;
139     read_pos      += bytes_read;
140     if (bytes_to_read > 0) {
141         return 0;
142     }
143 
144     // act
145     switch (h4_state) {
146         case H4_W4_PACKET_TYPE:
147             if (hci_event_buffer[0] == 4){
148                 read_pos = 0;
149                 bytes_to_read = 2;
150                 h4_state = H4_W4_EVENT_HEADER;
151             }
152             break;
153         case H4_W4_EVENT_HEADER:
154             bytes_to_read = hci_event_buffer[1];
155             h4_state = H4_W4_EVENT_PAYLOAD;
156             break;
157         case H4_W4_EVENT_PAYLOAD:
158             event_packet_handler(hci_event_buffer, read_pos);
159             h4_state = H4_W4_PACKET_TYPE;
160             read_pos = 0;
161             bytes_to_read = 1;
162             break;
163         case H4_W4_ACL_HEADER:
164             break;
165         case H4_W4_ACL_PAYLOAD:
166             break;
167     }
168     return 0;
169 }
170 
171 static const char * h4_get_transport_name(){
172     return "H4";
173 }
174 
175 static void dummy_handler(uint8_t *packet, int size){
176 }
177 
178 // single instance
179 hci_transport_t hci_h4_transport = {
180     h4_open,
181     h4_close,
182     h4_send_cmd_packet,
183     h4_send_acl_packet,
184     h4_register_event_packet_handler,
185     h4_register_acl_packet_handler,
186     h4_get_fd,
187     h4_handle_data,
188     h4_get_transport_name
189 };
190