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 BLUEKITCHEN
24 * GMBH 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_block_windows.c"
39
40 /*
41 * btstack_uart_block_windows.c
42 *
43 * Common code to access serial port via asynchronous block read/write commands
44 *
45 */
46 #include <Windows.h>
47 #include "btstack_uart_block.h"
48 #include "btstack_run_loop.h"
49 #include "btstack_debug.h"
50
51 #include <fcntl.h> /* File control definitions */
52 #include <string.h>
53 #include <errno.h>
54
55
56
57 // uart config
58 static const btstack_uart_config_t * uart_config;
59
60 // data source for integration with BTstack Runloop
61 static btstack_data_source_t transport_data_source_read;
62 static btstack_data_source_t transport_data_source_write;
63
64 // block write
65 static int write_bytes_len;
66 static const uint8_t * write_bytes_data;
67
68 // block read
69 static uint16_t read_bytes_len;
70 static uint8_t * read_bytes_data;
71
72 // callbacks
73 static void (*block_sent)(void);
74 static void (*block_received)(void);
75
76 // port and async control structure
77 static HANDLE serial_port_handle;
78 static OVERLAPPED overlapped_read;
79 static OVERLAPPED overlapped_write;
80
81 // fix for chipset drivers that need to download firmware before stack starts up
82 bool serial_port_open = false;
83
84 // -- engine that retries send/receive if not all bytes have been transferred
85
btstack_uart_windows_send_engine(void)86 static void btstack_uart_windows_send_engine(void){
87 // start write
88 DWORD bytes_written;
89 BOOL ok = WriteFile(serial_port_handle, // handle
90 write_bytes_data, // (LPCSTR) 8-bit data
91 write_bytes_len, // length
92 &bytes_written, // amount written
93 &overlapped_write); // overlapped structure
94
95 if (ok){
96 // assert all bytes written
97 if (bytes_written != write_bytes_len){
98 log_error("btstack_uart_windows_send_block: requested write %u but %u were written", (int) write_bytes_len, (int) bytes_written);
99 return;
100 }
101
102 //
103 // TODO: to defer sending done event by enabling POLL Callback for Write
104 //
105
106 // notify done
107 if (block_sent){
108 block_sent();
109 }
110 return;
111 }
112
113 DWORD err = GetLastError();
114 if (err != ERROR_IO_PENDING){
115 log_error("btstack_uart_windows_send_block: error writing");
116 return;
117 }
118
119 // IO_PENDING -> wait for completed
120 btstack_run_loop_enable_data_source_callbacks(&transport_data_source_write, DATA_SOURCE_CALLBACK_WRITE);
121 }
122
btstack_uart_windows_receive_engine(void)123 static void btstack_uart_windows_receive_engine(void){
124 DWORD bytes_read;
125 BOOL ok = ReadFile(serial_port_handle, // handle
126 read_bytes_data, // (LPCSTR) 8-bit data
127 read_bytes_len, // length
128 &bytes_read, // amount read
129 &overlapped_read); // overlapped structure
130
131 if (ok){
132 // assert all bytes read
133 if (bytes_read != read_bytes_len){
134 log_error("btstack_uart_windows_receive_block: requested read %u but %u were read", (int) read_bytes_len, (int) bytes_read);
135 return;
136 }
137
138 //
139 // TODO: to defer sending done event by enabling POLL Callback
140 //
141
142 // notify done
143 if (block_received){
144 block_received();
145 }
146 return;
147 }
148
149 DWORD err = GetLastError();
150 if (err != ERROR_IO_PENDING){
151 log_error("error reading");
152 return;
153 }
154
155 // IO_PENDING -> wait for completed
156 btstack_run_loop_enable_data_source_callbacks(&transport_data_source_read, DATA_SOURCE_CALLBACK_READ);
157 }
158
159
160 // -- overlapped IO handlers for read & write
161
btstack_uart_windows_process_write(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)162 static void btstack_uart_windows_process_write(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
163
164 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
165
166 DWORD bytes_written;
167 BOOL ok = GetOverlappedResult(serial_port_handle, &overlapped_write, &bytes_written, FALSE);
168 if(!ok){
169 DWORD err = GetLastError();
170 if (err == ERROR_IO_INCOMPLETE){
171 // IO_INCOMPLETE -> wait for completed
172 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
173 } else {
174 log_error("write: error writing");
175 }
176 return;
177 }
178
179 // assert all bytes written
180 if (bytes_written != write_bytes_len){
181 log_debug("write: requested to write %u but %u were written, try again", (int) write_bytes_len, (int) bytes_written);
182 btstack_uart_windows_send_engine();
183 write_bytes_data += bytes_written;
184 write_bytes_len -= bytes_written;
185 return;
186 }
187
188 // notify done
189 if (block_sent){
190 block_sent();
191 }
192 }
193
194
btstack_uart_windows_process_read(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)195 static void btstack_uart_windows_process_read(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
196
197 btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
198
199 DWORD bytes_read;
200 BOOL ok = GetOverlappedResult(serial_port_handle, &overlapped_read, &bytes_read, FALSE);
201 if(!ok){
202 DWORD err = GetLastError();
203 if (err == ERROR_IO_INCOMPLETE){
204 // IO_INCOMPLETE -> wait for completed
205 btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
206 } else {
207 log_error("error reading");
208 }
209 return;
210 }
211
212
213 // assert all bytes read
214 if (bytes_read != read_bytes_len){
215 log_debug("read: requested read %u but %u were read, try again", (int) read_bytes_len, (int) bytes_read);
216 read_bytes_data += bytes_read;
217 read_bytes_len -= (uint16_t) bytes_read;
218 btstack_uart_windows_receive_engine();
219 return;
220 }
221
222 // notify done
223 if (block_received){
224 block_received();
225 }
226 }
227
228 // -- API implementation
229
btstack_uart_windows_init(const btstack_uart_config_t * config)230 static int btstack_uart_windows_init(const btstack_uart_config_t * config){
231 uart_config = config;
232 return 0;
233 }
234
btstack_uart_windows_send_block(const uint8_t * data,uint16_t size)235 static void btstack_uart_windows_send_block(const uint8_t *data, uint16_t size){
236 // setup async write
237 write_bytes_data = data;
238 write_bytes_len = size;
239
240 // go
241 btstack_uart_windows_send_engine();
242 }
243
btstack_uart_windows_receive_block(uint8_t * buffer,uint16_t len)244 static void btstack_uart_windows_receive_block(uint8_t *buffer, uint16_t len){
245 // setup async read
246 read_bytes_data = buffer;
247 read_bytes_len = len;
248
249 // go
250 btstack_uart_windows_receive_engine();
251 }
252
btstack_uart_windows_set_baudrate_option(DCB * serial_params,uint32_t baudrate)253 static void btstack_uart_windows_set_baudrate_option(DCB * serial_params, uint32_t baudrate){
254 serial_params->BaudRate = baudrate;
255 }
256
btstack_uart_windows_set_parity_option(DCB * serial_params,uint32_t parity)257 static void btstack_uart_windows_set_parity_option(DCB * serial_params, uint32_t parity){
258 serial_params->Parity = parity;
259 }
260
btstack_uart_windows_set_flowcontrol_option(DCB * serial_params,uint32_t flowcontrol)261 static void btstack_uart_windows_set_flowcontrol_option(DCB * serial_params, uint32_t flowcontrol){
262 // Flowcontrol
263 serial_params->fOutxCtsFlow = flowcontrol;
264 serial_params->fRtsControl = flowcontrol ? RTS_CONTROL_HANDSHAKE : 0;
265 }
266
btstack_uart_windows_set_baudrate(uint32_t baudrate)267 static int btstack_uart_windows_set_baudrate(uint32_t baudrate){
268 DCB serial_params;
269 memset(&serial_params, 0, sizeof(DCB));
270 serial_params.DCBlength = sizeof(DCB);
271
272 int ok = GetCommState(serial_port_handle, &serial_params);
273 if (!ok){
274 log_error("windows_set_baudrate: Couldn't get serial parameters");
275 return -1;
276 }
277 btstack_uart_windows_set_baudrate_option(&serial_params, baudrate);
278 ok = SetCommState(serial_port_handle, &serial_params);
279 if (!ok){
280 log_error("windows_set_baudrate: Couldn't serial parameters");
281 return -1;
282 }
283
284 return 0;
285 }
286
btstack_uart_windows_set_parity(int parity)287 static int btstack_uart_windows_set_parity(int parity){
288 DCB serial_params;
289 memset(&serial_params, 0, sizeof(DCB));
290 serial_params.DCBlength = sizeof(DCB);
291
292 int ok = GetCommState(serial_port_handle, &serial_params);
293 if (!ok){
294 log_error("windows_set_parity: Couldn't get serial parameters");
295 return -1;
296 }
297 btstack_uart_windows_set_parity_option(&serial_params, parity);
298 ok = SetCommState(serial_port_handle, &serial_params);
299 if (!ok){
300 log_error("windows_set_parity: Couldn't serial parameters");
301 return -1;
302 }
303 return 0;
304 }
305
btstack_uart_windows_set_flowcontrol(int flowcontrol)306 static int btstack_uart_windows_set_flowcontrol(int flowcontrol){
307 DCB serial_params;
308 memset(&serial_params, 0, sizeof(DCB));
309 serial_params.DCBlength = sizeof(DCB);
310
311 int ok = GetCommState(serial_port_handle, &serial_params);
312 if (!ok){
313 log_error("windows_set_parity: Couldn't get serial parameters");
314 return -1;
315 }
316 btstack_uart_windows_set_flowcontrol_option(&serial_params, flowcontrol);
317 ok = SetCommState(serial_port_handle, &serial_params);
318 if (!ok){
319 log_error("windows_set_flowcontrol: Couldn't serial parameters");
320 return -1;
321 }
322 return 0;
323 }
324
btstack_uart_windows_open(void)325 static int btstack_uart_windows_open(void){
326
327 // allow to call open again
328 if (serial_port_open){
329 log_info("Serial port already open");
330 return 0;
331 }
332
333 const char * device_name = uart_config->device_name;
334 const uint32_t baudrate = uart_config->baudrate;
335 const int flowcontrol = uart_config->flowcontrol;
336
337 serial_port_handle = CreateFile( device_name,
338 GENERIC_READ | GENERIC_WRITE,
339 0,
340 0,
341 OPEN_EXISTING,
342 FILE_FLAG_OVERLAPPED,
343 0);
344
345 if (serial_port_handle == INVALID_HANDLE_VALUE){
346 log_error("windows_open: Unable to open port %s", device_name);
347 return -1;
348 }
349
350 DCB serial_params;
351 memset(&serial_params, 0, sizeof(DCB));
352 serial_params.DCBlength = sizeof(DCB);
353
354 int ok;
355
356 #if 0
357 // test - try to set internal buffer
358 ok = SetupComm(serial_port_handle, 64, 64);
359 printf("SetupCommL ok %u\n", ok);
360 #endif
361
362 #if 0
363 // test - read internal buffer sizes
364 COMMPROP comm_prop;
365 GetCommProperties(serial_port_handle, &comm_prop);
366 printf("dwMaxTxQueue %ld\n", comm_prop.dwMaxTxQueue);
367 printf("dwMaxRxQueue %ld\n", comm_prop.dwMaxRxQueue);
368 printf("dwCurrentTxQueue %ld\n", comm_prop.dwCurrentTxQueue);
369 printf("dwCurrentRxQueue %ld\n", comm_prop.dwCurrentRxQueue);
370 #endif
371
372 // Caveat: with the default FTDI driver and a FT232R on Windows 10, the default USB RX/TX buffer sizes are 4096
373 // this causes a problem when data is received back to back, like with SCO audio data
374
375 // Workaround: manually set these values in the Device Manager to 64 bytes
376
377 ok = GetCommState(serial_port_handle, &serial_params);
378
379 if (!ok){
380 log_error("windows_open: Couldn't get serial parameters");
381 return -1;
382 }
383
384 // 8-N-1
385 serial_params.ByteSize = 8;
386 serial_params.StopBits = ONESTOPBIT;
387 serial_params.Parity = NOPARITY;
388
389 // baudrate
390 btstack_uart_windows_set_baudrate_option(&serial_params, baudrate);
391
392 // flow control
393 btstack_uart_windows_set_flowcontrol_option(&serial_params, flowcontrol);
394
395 // parity none
396 btstack_uart_windows_set_parity_option(&serial_params, 0);
397
398 // commit changes
399 ok = SetCommState(serial_port_handle, &serial_params);
400 if (!ok){
401 log_error("windows_open: Couldn't serial parameters");
402 return -1;
403 }
404
405 // setup overlapped structures for async io
406 memset(&overlapped_read, 0, sizeof(overlapped_read));
407 memset(&overlapped_write, 0, sizeof(overlapped_write));
408 overlapped_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
409 overlapped_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
410
411 // setup read + write data sources
412 transport_data_source_read.source.handle = overlapped_read.hEvent;
413 transport_data_source_write.source.handle = overlapped_write.hEvent;
414 btstack_run_loop_set_data_source_handler(&transport_data_source_read, &btstack_uart_windows_process_read);
415 btstack_run_loop_set_data_source_handler(&transport_data_source_write, &btstack_uart_windows_process_write);
416 btstack_run_loop_add_data_source(&transport_data_source_read);
417 btstack_run_loop_add_data_source(&transport_data_source_write);
418
419 serial_port_open = true;
420
421 return 0;
422 }
423
btstack_uart_windows_close_new(void)424 static int btstack_uart_windows_close_new(void){
425
426 serial_port_open = false;
427
428 // first remove run loop handler
429 btstack_run_loop_remove_data_source(&transport_data_source_read);
430 btstack_run_loop_remove_data_source(&transport_data_source_write);
431
432 // note: an event cannot be freed while a kernel function is waiting.
433 // in our single-threaded environment, this cannot happen.
434
435 // free events
436 CloseHandle(overlapped_read.hEvent);
437 CloseHandle(overlapped_write.hEvent);
438 CloseHandle(serial_port_handle);
439
440 // set pointers to zero
441 overlapped_read.hEvent = NULL;
442 overlapped_write.hEvent = NULL;
443 serial_port_handle = NULL;
444 return 0;
445 }
446
btstack_uart_windows_set_block_received(void (* block_handler)(void))447 static void btstack_uart_windows_set_block_received( void (*block_handler)(void)){
448 block_received = block_handler;
449 }
450
btstack_uart_windows_set_block_sent(void (* block_handler)(void))451 static void btstack_uart_windows_set_block_sent( void (*block_handler)(void)){
452 block_sent = block_handler;
453 }
454
455 // static void btstack_uart_windows_set_sleep(uint8_t sleep){
456 // }
457 // static void btstack_uart_windows_set_csr_irq_handler( void (*csr_irq_handler)(void)){
458 // }
459
460 static const btstack_uart_block_t btstack_uart_windows = {
461 /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_windows_init,
462 /* int (*open)(void); */ &btstack_uart_windows_open,
463 /* int (*close)(void); */ &btstack_uart_windows_close_new,
464 /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_windows_set_block_received,
465 /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_windows_set_block_sent,
466 /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_windows_set_baudrate,
467 /* int (*set_parity)(int parity); */ &btstack_uart_windows_set_parity,
468 /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_windows_set_flowcontrol,
469 /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_windows_receive_block,
470 /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_windows_send_block,
471 /* int (*get_supported_sleep_modes); */ NULL,
472 /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL,
473 /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL,
474 NULL, NULL, NULL, NULL,
475 };
476
btstack_uart_block_windows_instance(void)477 const btstack_uart_block_t * btstack_uart_block_windows_instance(void){
478 return &btstack_uart_windows;
479 }
480