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