Skip to content

Commit

Permalink
Windows Handle GetOverlappedResult blocking on read/write (#129)
Browse files Browse the repository at this point in the history
- Implemented solution from issue signal11/hidapi#88
- Allows read/write frames up to 1000 per second
  • Loading branch information
CristianGlavana authored Sep 22, 2020
1 parent ad27b46 commit f7c7f97
Showing 1 changed file with 48 additions and 26 deletions.
74 changes: 48 additions & 26 deletions windows/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ struct hid_device_ {
BOOL read_pending;
char *read_buf;
OVERLAPPED ol;
OVERLAPPED write_ol;
};

static hid_device *new_hid_device()
Expand All @@ -159,13 +160,16 @@ static hid_device *new_hid_device()
dev->read_buf = NULL;
memset(&dev->ol, 0, sizeof(dev->ol));
dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
memset(&dev->write_ol, 0, sizeof(dev->write_ol));
dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);

return dev;
}

static void free_hid_device(hid_device *dev)
{
CloseHandle(dev->ol.hEvent);
CloseHandle(dev->write_ol.hEvent);
CloseHandle(dev->device_handle);
LocalFree(dev->last_error_str);
free(dev->read_buf);
Expand All @@ -176,6 +180,7 @@ static void register_error(hid_device *dev, const char *op)
{
WCHAR *ptr, *msg;

(void)op; // unreferenced param
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
Expand Down Expand Up @@ -629,12 +634,11 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)

int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
{
DWORD bytes_written;
DWORD bytes_written = 0;
BOOL res;
BOOL overlapped = FALSE;

OVERLAPPED ol;
unsigned char *buf;
memset(&ol, 0, sizeof(ol));

/* Make sure the right number of bytes are passed to WriteFile. Windows
expects the number of bytes which are in the _longest_ report (plus
Expand All @@ -654,7 +658,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
length = dev->output_report_length;
}

res = WriteFile(dev->device_handle, buf, (DWORD) length, NULL, &ol);
res = WriteFile(dev->device_handle, buf, (DWORD) length, NULL, &dev->write_ol);

if (!res) {
if (GetLastError() != ERROR_IO_PENDING) {
Expand All @@ -663,16 +667,28 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
bytes_written = -1;
goto end_of_function;
}
overlapped = TRUE;
}

/* Wait here until the write is done. This makes
hid_write() synchronous. */
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
if (!res) {
/* The Write operation failed. */
register_error(dev, "WriteFile");
bytes_written = -1;
goto end_of_function;
if (overlapped) {
/* Wait for the transaction to complete */
res = WaitForSingleObject(dev->write_ol.hEvent, 1000);
if (res != WAIT_OBJECT_0) {
/* There was a Timeout. */
bytes_written = -1;
register_error(dev, "WriteFile/WaitForSingleObject Timeout");
goto end_of_function;
}

/* Wait here until the write is done. This makes
hid_write() synchronous. */
res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*wait*/);
if (!res) {
/* The Write operation failed. */
register_error(dev, "WriteFile");
bytes_written = -1;
goto end_of_function;
}
}

end_of_function:
Expand All @@ -688,6 +704,7 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
DWORD bytes_read = 0;
size_t copy_len = 0;
BOOL res;
BOOL overlapped = FALSE;

/* Copy the handle for convenience. */
HANDLE ev = dev->ol.hEvent;
Expand All @@ -707,24 +724,29 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
dev->read_pending = FALSE;
goto end_of_function;
}
}
overlapped = TRUE;
}
}
else {
overlapped = TRUE;
}

if (milliseconds >= 0) {
/* See if there is any data yet. */
res = WaitForSingleObject(ev, milliseconds);
if (res != WAIT_OBJECT_0) {
/* There was no data this time. Return zero bytes available,
but leave the Overlapped I/O running. */
return 0;
if (overlapped) {
if (milliseconds >= 0) {
/* See if there is any data yet. */
res = WaitForSingleObject(ev, milliseconds);
if (res != WAIT_OBJECT_0) {
/* There was no data this time. Return zero bytes available,
but leave the Overlapped I/O running. */
return 0;
}
}
}

/* Either WaitForSingleObject() told us that ReadFile has completed, or
we are in non-blocking mode. Get the number of bytes read. The actual
data has been copied to the data[] array which was passed to ReadFile(). */
res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);

/* Either WaitForSingleObject() told us that ReadFile has completed, or
we are in non-blocking mode. Get the number of bytes read. The actual
data has been copied to the data[] array which was passed to ReadFile(). */
res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
}
/* Set pending back to false, even if GetOverlappedResult() returned error. */
dev->read_pending = FALSE;

Expand Down

0 comments on commit f7c7f97

Please sign in to comment.