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