Skip to content

Commit

Permalink
hid_write[_timeout]: add _timeout versions of hid_write
Browse files Browse the repository at this point in the history
* linux: Use poll(2) to see if we can write before we actually write(2).  Also add loop in hid_write() to make it infinite in case of timeout (per signal11#190).
* libusb: Pass the milliseconds value to libusb_*_transfer() functions (adjusting for -1/0 differences).
* windows: Currently returns -1.  Needs to be written (by someone other than me).
* mac: Currently returns -1.  Needs to be written (by someone other than me).
  • Loading branch information
jsquyres committed Nov 10, 2014
1 parent 0d4cf6c commit 614c613
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 5 deletions.
15 changes: 15 additions & 0 deletions hidapi/hidapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,21 @@ extern "C" {
*/
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);

/** @brief Write an Output report to a HID device with timeout.
This function is just like hid_write(), but with a timeout value.
@ingroup API
@param device A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send.
@param milliseconds timeout in milliseconds or -1 for blocking wait.
@returns
This function returns the actual number of bytes written and
-1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_write_timeout(hid_device *device, const unsigned char *data, size_t length, int milliseconds);

/** @brief Write an Output report to a HID device.
The first byte of @p data[] must contain the Report ID. For
Expand Down
22 changes: 19 additions & 3 deletions libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
}


int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
int HID_API_EXPORT hid_write_timeout(hid_device *dev, const unsigned char *data, size_t length, int milliseconds)
{
int res;
int report_number = data[0];
Expand All @@ -1012,6 +1012,16 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t
skipped_report_id = 1;
}

/* milliseconds==-1 is an infinite timeout to hidapi, but 0 is
* an infinite timeout to libusb_*_transfer(). Hence, if the
* caller asks for 0, make it 1. If the caller asks for <0,
* make it 0. */
if (milliseconds == 0) {
milliseconds = -1;
}
else if (milliseconds < 0) {
milliseconds = 0;
}

if (dev->output_endpoint <= 0) {
/* No interrput out endpoint. Use the Control Endpoint */
Expand All @@ -1021,7 +1031,7 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t
(2/*HID output*/ << 8) | report_number,
dev->interface,
(unsigned char *)data, length,
0/*timeout millis*/);
milliseconds/*timeout millis*/);

if (res < 0)
return -1;
Expand All @@ -1038,7 +1048,7 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t
dev->output_endpoint,
(unsigned char*)data,
length,
&actual_length, 0);
&actual_length, milliseconds);

if (res < 0)
return -1;
Expand All @@ -1050,6 +1060,12 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t
}
}

int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
{
hid_write_timeout(dev, data, length, -1);
}


/* Helper function, to simplify hid_read().
This should be called with dev->mutex locked. */
static int return_data(hid_device *dev, unsigned char *data, size_t length)
Expand Down
36 changes: 34 additions & 2 deletions linux/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,16 +663,48 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
}


int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
int HID_API_EXPORT hid_write_timeout(hid_device *dev, const unsigned char *data, size_t length, int milliseconds)
{
int bytes_written;
int ret, bytes_written;
struct pollfd fds;

fds.fd = dev->device_handle;
fds.events = POLLOUT;
fds.revents = 0;
ret = poll(&fds, 1, milliseconds);
if (ret == -1 || ret == 0) {
/* Error or timeout */
return ret;
}
else {
/* Check for errors on the file descriptor. This will
indicate a device disconnection. */
if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
return -1;
}

bytes_written = write(dev->device_handle, data, length);

return bytes_written;
}


int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
{
int bytes_written;

while (1) {
bytes_written = write(dev->device_handle, data, length);
if (bytes_written < 0 &&
(errno == ETIMEDOUT || errno == EINTR)) {
continue;
}

return bytes_written;
}
}


int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
{
int bytes_read;
Expand Down
6 changes: 6 additions & 0 deletions mac/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,12 @@ static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char
return -1;
}

int HID_API_EXPORT hid_write_timeout(hid_device *dev, const unsigned char *data, size_t length, int milliseconds)
{
/* JMS Needs to be written by someone other than me... */
return -1;
}

int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
{
return set_report(dev, kIOHIDReportTypeOutput, data, length);
Expand Down
6 changes: 6 additions & 0 deletions windows/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,12 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
return NULL;
}

int HID_API_EXPORT hid_write_timeout(hid_device *dev, const unsigned char *data, size_t length, int milliseconds)
{
/* JMS Needs to be written by someone other than me... */
return -1;
}

int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
{
DWORD bytes_written;
Expand Down

0 comments on commit 614c613

Please sign in to comment.