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 }; 416 417 const btstack_uart_block_t * btstack_uart_block_windows_instance(void){ 418 return &btstack_uart_windows; 419 }