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