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