xref: /btstack/platform/windows/btstack_uart_block_windows.c (revision b795dcd07cafa39590ef7b7e12c7051fdb8ae36a)
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