xref: /btstack/platform/windows/btstack_uart_block_windows.c (revision c3dafd4604b9c4bb7427d6d98556c681fa2f50a6)
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 
233 static int btstack_uart_windows_set_baudrate(uint32_t baudrate){
234     DCB serial_params;
235     memset(&serial_params, 0, sizeof(DCB));
236     serial_params.DCBlength = sizeof(DCB);
237 
238     int ok = GetCommState(serial_port_handle, &serial_params);
239 
240     if (!ok){
241         log_error("windows_set_baudrate: Couldn't get serial parameters");
242         return -1;
243     }
244 
245     serial_params.BaudRate = baudrate;
246 
247     ok = SetCommState(serial_port_handle, &serial_params);
248     if (!ok){
249         log_error("windows_set_baudrate: Couldn't serial parameters");
250         return -1;
251     }
252 
253     return 0;
254 }
255 
256 
257 static int btstack_uart_windows_set_parity(int parity){
258     DCB serial_params;
259     memset(&serial_params, 0, sizeof(DCB));
260     serial_params.DCBlength = sizeof(DCB);
261 
262     int ok = GetCommState(serial_port_handle, &serial_params);
263 
264     if (!ok){
265         log_error("windows_set_parity: Couldn't get serial parameters");
266         return -1;
267     }
268 
269     serial_params.Parity = parity;
270 
271     ok = SetCommState(serial_port_handle, &serial_params);
272     if (!ok){
273         log_error("windows_set_parity: Couldn't serial parameters");
274         return -1;
275     }
276     return 0;
277 }
278 
279 static int btstack_uart_windows_open(void){
280 
281     const char * device_name = uart_config->device_name;
282     const uint32_t baudrate  = uart_config->baudrate;
283     const int flowcontrol    = uart_config->flowcontrol;
284 
285     serial_port_handle = CreateFile( device_name,
286                         GENERIC_READ | GENERIC_WRITE,
287                         0,
288                         0,
289                         OPEN_EXISTING,
290                         FILE_FLAG_OVERLAPPED,
291                         0);
292 
293     if (device_name == INVALID_HANDLE_VALUE){
294         log_error("windows_open: Unable to open port %s", device_name);
295         return -1;
296     }
297 
298     DCB serial_params;
299     memset(&serial_params, 0, sizeof(DCB));
300     serial_params.DCBlength = sizeof(DCB);
301 
302     int ok;
303 
304 #if 0
305     // test - try to set internal buffer
306     ok = SetupComm(serial_port_handle, 64, 64);
307     printf("SetupCommL ok %u\n", ok);
308 #endif
309 
310 #if 0
311     // test - read internal buffer sizes
312     COMMPROP comm_prop;
313     GetCommProperties(serial_port_handle, &comm_prop);
314     printf("dwMaxTxQueue %ld\n", comm_prop.dwMaxTxQueue);
315     printf("dwMaxRxQueue %ld\n", comm_prop.dwMaxRxQueue);
316     printf("dwCurrentTxQueue %ld\n", comm_prop.dwCurrentTxQueue);
317     printf("dwCurrentRxQueue %ld\n", comm_prop.dwCurrentRxQueue);
318 #endif
319 
320     // Caveat: with the default FTDI driver and a FT232R on Windows 10, the default USB RX/TX buffer sizes are 4096
321     // this causes a problem when data is received back to back, like with SCO audio data
322 
323     // Workaround: manually set these values in the Device Manager to 64 bytes
324 
325     ok = GetCommState(serial_port_handle, &serial_params);
326 
327     if (!ok){
328         log_error("windows_open: Couldn't get serial parameters");
329         return -1;
330     }
331 
332     // 8-N-1
333     serial_params.ByteSize     = 8;
334     serial_params.StopBits     = ONESTOPBIT;
335     serial_params.Parity       = NOPARITY;
336 
337     // Flowcontrol
338     serial_params.fOutxCtsFlow = flowcontrol;
339     serial_params.fRtsControl  = flowcontrol ? RTS_CONTROL_HANDSHAKE : 0;
340 
341     ok = SetCommState(serial_port_handle, &serial_params);
342     if (!ok){
343         log_error("windows_open: Couldn't serial parameters");
344         return -1;
345     }
346 
347     // also set baudrate
348     if (btstack_uart_windows_set_baudrate(baudrate) < 0){
349         return -1;
350     }
351 
352     // setup overlapped structures for async io
353     memset(&overlapped_read,  0, sizeof(overlapped_read));
354     memset(&overlapped_write, 0, sizeof(overlapped_write));
355     overlapped_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
356     overlapped_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
357 
358     // setup read + write data sources
359     transport_data_source_read.handle = overlapped_read.hEvent;
360     transport_data_source_write.handle = overlapped_write.hEvent;
361     btstack_run_loop_set_data_source_handler(&transport_data_source_read,  &btstack_uart_windows_process_read);
362     btstack_run_loop_set_data_source_handler(&transport_data_source_write, &btstack_uart_windows_process_write);
363     btstack_run_loop_add_data_source(&transport_data_source_read);
364     btstack_run_loop_add_data_source(&transport_data_source_write);
365 
366     return 0;
367 }
368 
369 static int btstack_uart_windows_close_new(void){
370 
371     // first remove run loop handler
372     btstack_run_loop_remove_data_source(&transport_data_source_read);
373     btstack_run_loop_remove_data_source(&transport_data_source_write);
374 
375     // note: an event cannot be freed while a kernel function is waiting.
376     //       in our single-threaded environment, this cannot happen.
377 
378     // free events
379     CloseHandle(overlapped_read.hEvent);
380     CloseHandle(overlapped_write.hEvent);
381     CloseHandle(serial_port_handle);
382 
383     // set pointers to zero
384     overlapped_read.hEvent = NULL;
385     overlapped_write.hEvent = NULL;
386     serial_port_handle = NULL;
387     return 0;
388 }
389 
390 static void btstack_uart_windows_set_block_received( void (*block_handler)(void)){
391     block_received = block_handler;
392 }
393 
394 static void btstack_uart_windows_set_block_sent( void (*block_handler)(void)){
395     block_sent = block_handler;
396 }
397 
398 // static void btstack_uart_windows_set_sleep(uint8_t sleep){
399 // }
400 // static void btstack_uart_windows_set_csr_irq_handler( void (*csr_irq_handler)(void)){
401 // }
402 
403 static const btstack_uart_block_t btstack_uart_windows = {
404     /* int  (*init)(hci_transport_config_uart_t * config); */         &btstack_uart_windows_init,
405     /* int  (*open)(void); */                                         &btstack_uart_windows_open,
406     /* int  (*close)(void); */                                        &btstack_uart_windows_close_new,
407     /* void (*set_block_received)(void (*handler)(void)); */          &btstack_uart_windows_set_block_received,
408     /* void (*set_block_sent)(void (*handler)(void)); */              &btstack_uart_windows_set_block_sent,
409     /* int  (*set_baudrate)(uint32_t baudrate); */                    &btstack_uart_windows_set_baudrate,
410     /* int  (*set_parity)(int parity); */                             &btstack_uart_windows_set_parity,
411     /* void (*receive_block)(uint8_t *buffer, uint16_t len); */       &btstack_uart_windows_receive_block,
412     /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_windows_send_block,
413     /* int (*get_supported_sleep_modes); */                           NULL,
414     /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */    NULL,
415     /* void (*set_wakeup_handler)(void (*handler)(void)); */          NULL,
416 };
417 
418 const btstack_uart_block_t * btstack_uart_block_windows_instance(void){
419 	return &btstack_uart_windows;
420 }