1 /*
2 * Copyright (C) 2016 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "btstack_uart_posix.c"
39
40 /*
41 * btstack_uart_block_posix.c
42 *
43 * Common code to access serial port via asynchronous block read/write commands
44 *
45 */
46
47 #include "btstack_uart_block.h"
48 #include "btstack_run_loop.h"
49 #include "btstack_debug.h"
50
51 #include <termios.h> /* POSIX terminal control definitions */
52 #include <fcntl.h> /* File control definitions */
53 #include <unistd.h> /* UNIX standard function definitions */
54 #include <string.h>
55 #include <errno.h>
56 #ifdef __APPLE__
57 #include <sys/ioctl.h>
58 #include <IOKit/serial/ioss.h>
59 #endif
60
61 // uart config
62 static const btstack_uart_config_t * uart_config;
63
64 // data source for integration with BTstack Runloop
65 static btstack_data_source_t transport_data_source;
66
67 // block write
68 static int write_bytes_len;
69 static const uint8_t * write_bytes_data;
70
71 // block read
72 static uint16_t read_bytes_len;
73 static uint8_t * read_bytes_data;
74
75 // callbacks
76 static void (*block_sent)(void);
77 static void (*block_received)(void);
78
79
btstack_uart_posix_init(const btstack_uart_config_t * config)80 static int btstack_uart_posix_init(const btstack_uart_config_t * config){
81 uart_config = config;
82 return 0;
83 }
84
btstack_uart_posix_process_write(btstack_data_source_t * ds)85 static void btstack_uart_posix_process_write(btstack_data_source_t *ds) {
86
87 if (write_bytes_len == 0) return;
88
89 uint32_t start = btstack_run_loop_get_time_ms();
90
91 // write up to write_bytes_len to fd
92 int bytes_written = (int) write(ds->source.fd, write_bytes_data, write_bytes_len);
93 if (bytes_written < 0) {
94 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
95 return;
96 }
97
98 uint32_t end = btstack_run_loop_get_time_ms();
99 if (end - start > 10){
100 log_info("h4_process: write took %u ms", end - start);
101 }
102
103 write_bytes_data += bytes_written;
104 write_bytes_len -= bytes_written;
105
106 if (write_bytes_len){
107 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
108 return;
109 }
110
111 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
112
113 // notify done
114 if (block_sent){
115 block_sent();
116 }
117 }
118
btstack_uart_posix_process_read(btstack_data_source_t * ds)119 static void btstack_uart_posix_process_read(btstack_data_source_t *ds) {
120
121 if (read_bytes_len == 0) {
122 log_info("btstack_uart_posix_process_read but no read requested");
123 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
124 }
125
126 uint32_t start = btstack_run_loop_get_time_ms();
127
128 // read up to bytes_to_read data in
129 ssize_t bytes_read = read(ds->source.fd, read_bytes_data, read_bytes_len);
130 // log_info("btstack_uart_posix_process_read need %u bytes, got %d", read_bytes_len, (int) bytes_read);
131 uint32_t end = btstack_run_loop_get_time_ms();
132 if (end - start > 10){
133 log_info("h4_process: read took %u ms", end - start);
134 }
135 if (bytes_read < 0) return;
136
137 read_bytes_len -= bytes_read;
138 read_bytes_data += bytes_read;
139 if (read_bytes_len > 0) return;
140
141 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
142
143 if (block_received){
144 block_received();
145 }
146 }
147
hci_transport_h5_process(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)148 static void hci_transport_h5_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
149 if (ds->source.fd < 0) return;
150 switch (callback_type){
151 case DATA_SOURCE_CALLBACK_READ:
152 btstack_uart_posix_process_read(ds);
153 break;
154 case DATA_SOURCE_CALLBACK_WRITE:
155 btstack_uart_posix_process_write(ds);
156 break;
157 default:
158 break;
159 }
160 }
161
btstack_uart_posix_set_baudrate(uint32_t baudrate)162 static int btstack_uart_posix_set_baudrate(uint32_t baudrate){
163 UNUSED(baudrate);
164 #if 0
165 int fd = transport_data_source.source.fd;
166
167 log_info("h4_set_baudrate %u", baudrate);
168
169 #ifdef __APPLE__
170
171 // From https://developer.apple.com/library/content/samplecode/SerialPortSample/Listings/SerialPortSample_SerialPortSample_c.html
172
173 // The IOSSIOSPEED ioctl can be used to set arbitrary baud rates
174 // other than those specified by POSIX. The driver for the underlying serial hardware
175 // ultimately determines which baud rates can be used. This ioctl sets both the input
176 // and output speed.
177
178 speed_t speed = baudrate;
179 if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
180 log_error("btstack_uart_posix_set_baudrate: error calling ioctl(..., IOSSIOSPEED, %u) - %s(%d).\n", baudrate, strerror(errno), errno);
181 return -1;
182 }
183
184 #else
185 struct termios toptions;
186
187 if (tcgetattr(fd, &toptions) < 0) {
188 log_error("btstack_uart_posix_set_baudrate: Couldn't get term attributes");
189 return -1;
190 }
191
192 speed_t brate = baudrate; // let you override switch below if needed
193 switch(baudrate) {
194 case 57600: brate=B57600; break;
195 case 115200: brate=B115200; break;
196 #ifdef B230400
197 case 230400: brate=B230400; break;
198 #endif
199 #ifdef B460800
200 case 460800: brate=B460800; break;
201 #endif
202 #ifdef B921600
203 case 921600: brate=B921600; break;
204 #endif
205
206 cfsetospeed(&toptions, brate);
207 cfsetispeed(&toptions, brate);
208
209 if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
210 log_error("btstack_uart_posix_set_baudrate: Couldn't set term attributes");
211 return -1;
212 }
213 #endif
214 #endif
215 return 0;
216 }
217
218 static void btstack_uart_posix_set_parity_option(struct termios * toptions, int parity){
219 if (parity){
220 // enable even parity
221 toptions->c_cflag |= PARENB;
222 } else {
223 // disable even parity
224 toptions->c_cflag &= ~PARENB;
225 }
226 }
227
228 static void btstack_uart_posix_set_flowcontrol_option(struct termios * toptions, int flowcontrol){
229 if (flowcontrol) {
230 // with flow control
231 toptions->c_cflag |= CRTSCTS;
232 } else {
233 // no flow control
234 toptions->c_cflag &= ~CRTSCTS;
235 }
236 }
237
238 static int btstack_uart_posix_set_parity(int parity){
239 int fd = transport_data_source.source.fd;
240 struct termios toptions;
241 if (tcgetattr(fd, &toptions) < 0) {
242 log_error("btstack_uart_posix_set_parity: Couldn't get term attributes");
243 return -1;
244 }
245 btstack_uart_posix_set_parity_option(&toptions, parity);
246 if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
247 log_error("posix_set_parity: Couldn't set term attributes");
248 return -1;
249 }
250 return 0;
251 }
252
253
254 static int btstack_uart_posix_set_flowcontrol(int flowcontrol){
255 int fd = transport_data_source.source.fd;
256 struct termios toptions;
257 if (tcgetattr(fd, &toptions) < 0) {
258 log_error("btstack_uart_posix_set_parity: Couldn't get term attributes");
259 return -1;
260 }
261 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol);
262 if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
263 log_error("posix_set_flowcontrol: Couldn't set term attributes");
264 return -1;
265 }
266 return 0;
267 }
268
269 static int btstack_uart_posix_open(void){
270
271 const char * device_name = uart_config->device_name;
272 const int flowcontrol = uart_config->flowcontrol;
273 const uint32_t baudrate = uart_config->baudrate;
274
275 struct termios toptions;
276 int flags = O_RDWR | O_NOCTTY | O_NONBLOCK;
277 int fd = open(device_name, flags);
278 if (fd == -1) {
279 log_error("posix_open: Unable to open port %s", device_name);
280 return -1;
281 }
282
283 if (tcgetattr(fd, &toptions) < 0) {
284 log_error("posix_open: Couldn't get term attributes");
285 return -1;
286 }
287
288 cfmakeraw(&toptions); // make raw
289
290 // 8N1
291 toptions.c_cflag &= ~CSTOPB;
292 toptions.c_cflag |= CS8;
293
294 toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
295 toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
296
297 // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
298 toptions.c_cc[VMIN] = 1;
299 toptions.c_cc[VTIME] = 0;
300
301 // no parity
302 btstack_uart_posix_set_parity_option(&toptions, 0);
303
304 // flowcontrol
305 btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol);
306
307 if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
308 log_error("posix_open: Couldn't set term attributes");
309 return -1;
310 }
311
312 // store fd in data source
313 transport_data_source.source.fd = fd;
314
315 // also set baudrate
316 if (btstack_uart_posix_set_baudrate(baudrate) < 0){
317 return -1;
318 }
319
320 // set up data_source
321 btstack_run_loop_set_data_source_fd(&transport_data_source, fd);
322 btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_transport_h5_process);
323 btstack_run_loop_add_data_source(&transport_data_source);
324
325 // wait a bit - at least cheap FTDI232 clones might send the first byte out incorrectly
326 usleep(100000);
327
328 return 0;
329 }
330
331 static int btstack_uart_posix_close_new(void){
332
333 // first remove run loop handler
334 btstack_run_loop_remove_data_source(&transport_data_source);
335
336 // then close device
337 close(transport_data_source.source.fd);
338 transport_data_source.source.fd = -1;
339 return 0;
340 }
341
342 static void btstack_uart_posix_set_block_received( void (*block_handler)(void)){
343 block_received = block_handler;
344 }
345
346 static void btstack_uart_posix_set_block_sent( void (*block_handler)(void)){
347 block_sent = block_handler;
348 }
349
350 static void btstack_uart_posix_send_block(const uint8_t *data, uint16_t size){
351 // setup async write
352 write_bytes_data = data;
353 write_bytes_len = size;
354
355 // go
356 // btstack_uart_posix_process_write(&transport_data_source);
357 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE);
358 }
359
360 static void btstack_uart_posix_receive_block(uint8_t *buffer, uint16_t len){
361 read_bytes_data = buffer;
362 read_bytes_len = len;
363 btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ);
364
365 // go
366 // btstack_uart_posix_process_read(&transport_data_source);
367 }
368
369 // static void btstack_uart_posix_set_sleep(uint8_t sleep){
370 // }
371 // static void btstack_uart_posix_set_csr_irq_handler( void (*csr_irq_handler)(void)){
372 // }
373
374 static const btstack_uart_block_t btstack_uart_posix = {
375 /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_posix_init,
376 /* int (*open)(void); */ &btstack_uart_posix_open,
377 /* int (*close)(void); */ &btstack_uart_posix_close_new,
378 /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_posix_set_block_received,
379 /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_posix_set_block_sent,
380 /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_posix_set_baudrate,
381 /* int (*set_parity)(int parity); */ &btstack_uart_posix_set_parity,
382 /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_posix_set_flowcontrol,
383 /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_posix_receive_block,
384 /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_posix_send_block,
385 /* int (*get_supported_sleep_modes); */ NULL,
386 /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL,
387 /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL,
388 NULL, NULL, NULL, NULL,
389 };
390
391 const btstack_uart_block_t * btstack_uart_posix_instance(void){
392 return &btstack_uart_posix;
393 }
394