From 5b81efe2932eb28c77d4817bca75c0006be99b68 Mon Sep 17 00:00:00 2001
From: Matthias Ringwald <matthias@ringwald.ch>
Date: Thu, 4 Jan 2018 17:21:25 +0100
Subject: [PATCH] windows: repeat UART read/write operation if not all bytes
 have been read or written

---
 platform/windows/btstack_uart_block_windows.c | 179 ++++++++++--------
 1 file changed, 99 insertions(+), 80 deletions(-)

diff --git a/platform/windows/btstack_uart_block_windows.c b/platform/windows/btstack_uart_block_windows.c
index 17e6d664d..2909dabad 100644
--- a/platform/windows/btstack_uart_block_windows.c
+++ b/platform/windows/btstack_uart_block_windows.c
@@ -79,76 +79,9 @@ static HANDLE serial_port_handle;
 static OVERLAPPED overlapped_read;
 static OVERLAPPED overlapped_write;
 
+// -- engine that retries send/receive if not all bytes have been transferred
 
-static int btstack_uart_windows_init(const btstack_uart_config_t * config){
-    uart_config = config;
-    return 0;
-}
-
-static void btstack_uart_windows_process_write(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
-
-    btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
-
-    DWORD bytes_written;
-    BOOL ok = GetOverlappedResult(serial_port_handle, &overlapped_write, &bytes_written, FALSE);
-    if(!ok){
-        DWORD err = GetLastError();
-        if (err == ERROR_IO_INCOMPLETE){
-            // IO_INCOMPLETE -> wait for completed
-            btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
-        } else {
-            log_error("btstack_uart_windows_process_write: error writing");
-        }
-        return;
-    }
-
-    // assert all bytes written
-    if (bytes_written != write_bytes_len){
-        log_error("btstack_uart_windows_process_write: requested write %u but %u were written", (int) write_bytes_len, (int) bytes_written);
-        return;
-    }
-
-    // notify done
-    if (block_sent){
-        block_sent();
-    }
-}
-
-static void btstack_uart_windows_process_read(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
-
-    btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
-
-    DWORD bytes_read;
-    BOOL ok = GetOverlappedResult(serial_port_handle, &overlapped_read, &bytes_read, FALSE);
-    if(!ok){
-        DWORD err = GetLastError();
-        if (err == ERROR_IO_INCOMPLETE){
-            // IO_INCOMPLETE -> wait for completed
-            btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
-        } else {
-            log_error("btstack_uart_windows_process_write: error writing");
-        }
-        return;
-    }
-
-    // assert all bytes read
-    if (bytes_read != read_bytes_len){
-        log_error("btstack_uart_windows_process_read: requested read %u but %u were read", (int)  read_bytes_len, (int)  bytes_read);
-        return;
-    }
-
-    // notify done
-    if (block_received){
-        block_received();
-    }
-}
-
-static void btstack_uart_windows_send_block(const uint8_t *data, uint16_t size){
-
-    // setup async write
-    write_bytes_data = data;
-    write_bytes_len  = size;
-
+static void btstack_uart_windows_send_engine(void){
     // start write
     DWORD bytes_written;
     BOOL ok = WriteFile(serial_port_handle,  // handle
@@ -158,7 +91,6 @@ static void btstack_uart_windows_send_block(const uint8_t *data, uint16_t size){
                         &overlapped_write);  // overlapped structure
 
     if (ok){
-
         // assert all bytes written
         if (bytes_written != write_bytes_len){
             log_error("btstack_uart_windows_send_block: requested write %u but %u were written", (int) write_bytes_len, (int) bytes_written);
@@ -186,13 +118,7 @@ static void btstack_uart_windows_send_block(const uint8_t *data, uint16_t size){
     btstack_run_loop_enable_data_source_callbacks(&transport_data_source_write, DATA_SOURCE_CALLBACK_WRITE);
 }
 
-static void btstack_uart_windows_receive_block(uint8_t *buffer, uint16_t len){
-
-    // setup async read
-    read_bytes_data = buffer;
-    read_bytes_len = len;
-
-    // go
+static void btstack_uart_windows_receive_engine(void){
     DWORD bytes_read;
     BOOL ok = ReadFile(serial_port_handle,  // handle
                         read_bytes_data,    // (LPCSTR) 8-bit data
@@ -201,7 +127,6 @@ static void btstack_uart_windows_receive_block(uint8_t *buffer, uint16_t len){
                         &overlapped_read);  // overlapped structure
 
     if (ok){
-
         // assert all bytes read
         if (bytes_read != read_bytes_len){
             log_error("btstack_uart_windows_receive_block: requested read %u but %u were read", (int) read_bytes_len, (int) bytes_read);
@@ -221,7 +146,7 @@ static void btstack_uart_windows_receive_block(uint8_t *buffer, uint16_t len){
 
     DWORD err = GetLastError();
     if (err != ERROR_IO_PENDING){
-        log_error("btstack_uart_windows_receive_block: error reading");
+        log_error("error reading");
         return;
     }
 
@@ -229,6 +154,100 @@ static void btstack_uart_windows_receive_block(uint8_t *buffer, uint16_t len){
     btstack_run_loop_enable_data_source_callbacks(&transport_data_source_read, DATA_SOURCE_CALLBACK_READ);
 }
 
+
+// -- overlapped IO handlers for read & write
+
+static void btstack_uart_windows_process_write(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
+
+    btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
+
+    DWORD bytes_written;
+    BOOL ok = GetOverlappedResult(serial_port_handle, &overlapped_write, &bytes_written, FALSE);
+    if(!ok){
+        DWORD err = GetLastError();
+        if (err == ERROR_IO_INCOMPLETE){
+            // IO_INCOMPLETE -> wait for completed
+            btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
+        } else {
+            log_error("write: error writing");
+        }
+        return;
+    }
+
+    // assert all bytes written
+    if (bytes_written != write_bytes_len){
+        log_debug("write: requested to write %u but %u were written, try again", (int) write_bytes_len, (int) bytes_written);
+        btstack_uart_windows_send_engine();
+        write_bytes_data += bytes_written;
+        write_bytes_len  -= bytes_written;
+        return;
+    }
+
+    // notify done
+    if (block_sent){
+        block_sent();
+    }
+}
+
+
+static void btstack_uart_windows_process_read(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
+
+    btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
+
+    DWORD bytes_read;
+    BOOL ok = GetOverlappedResult(serial_port_handle, &overlapped_read, &bytes_read, FALSE);
+    if(!ok){
+        DWORD err = GetLastError();
+        if (err == ERROR_IO_INCOMPLETE){
+            // IO_INCOMPLETE -> wait for completed
+            btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
+        } else {
+            log_error("error reading");
+        }
+        return;
+    }
+
+
+    // assert all bytes read
+    if (bytes_read != read_bytes_len){
+        log_debug("read: requested read %u but %u were read, try again", (int)  read_bytes_len, (int)  bytes_read);
+        read_bytes_data += bytes_read;
+        read_bytes_len  -= bytes_read;
+        btstack_uart_windows_receive_engine();
+        return;
+    }
+
+    // notify done
+    if (block_received){
+        block_received();
+    }
+}
+
+// -- API implementation
+
+static int btstack_uart_windows_init(const btstack_uart_config_t * config){
+    uart_config = config;
+    return 0;
+}
+
+static void btstack_uart_windows_send_block(const uint8_t *data, uint16_t size){
+    // setup async write
+    write_bytes_data = data;
+    write_bytes_len  = size;
+
+    // go
+    btstack_uart_windows_send_engine();
+}
+
+static void btstack_uart_windows_receive_block(uint8_t *buffer, uint16_t len){
+    // setup async read
+    read_bytes_data = buffer;
+    read_bytes_len = len;
+
+    // go
+    btstack_uart_windows_receive_engine();
+}
+
 static void btstack_uart_windows_set_baudrate_option(DCB * serial_params, uint32_t baudrate){
     serial_params->BaudRate = baudrate;
 }
@@ -444,4 +463,4 @@ static const btstack_uart_block_t btstack_uart_windows = {
 
 const btstack_uart_block_t * btstack_uart_block_windows_instance(void){
 	return &btstack_uart_windows;
-}
\ No newline at end of file
+}