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 }