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