Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions hid_disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,24 @@ func (dev *Device) GetInputReport(b []byte) (int, error) {
return 0, ErrUnsupportedPlatform
}

// SendOutputReport sends a output report to a HID device
//
// Output reports are sent over the Control endpoint as a
// Set_Report transfer. The first byte of @p data[] must
// contain the Report ID. For devices which only support a
// single report, this must be set to 0x0. The remaining bytes
// contain the report data. Since the Report ID is mandatory,
// calls to SendOutputReport() will always contain one
// more byte than the report contains. For example, if a hid
// report is 16 bytes long, 17 bytes must be passed to
// SendOutputReport(): the Report ID (or 0x0, for
// devices which do not use numbered reports), followed by the
// report data (16 bytes). In this example, the length passed
// in would be 17.
func (dev *Device) SendOutputReport(b []byte) (int, error) {
return 0, ErrUnsupportedPlatform
}

// SetNonblocking sets the device handle to be non-blocking.
//
// In non-blocking mode calls to Read() will return
Expand Down
54 changes: 52 additions & 2 deletions hid_enabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ readAgain:
return 0, ErrDeviceClosed
}
// Device not closed, some other error occurred
message := C.hid_error(device)
message := C.hid_read_error(device)
if message == nil {
return 0, errors.New("hidapi: unknown failure")
}
Expand Down Expand Up @@ -363,7 +363,7 @@ readAgain:
return 0, ErrDeviceClosed
}
// Device not closed, some other error occurred
message := C.hid_error(device)
message := C.hid_read_error(device)
if message == nil {
return 0, errors.New("hidapi: unknown failure")
}
Expand Down Expand Up @@ -459,6 +459,56 @@ func (dev *Device) GetInputReport(b []byte) (int, error) {
return read, nil
}

// SendOutputReport sends a output report to a HID device
//
// Output reports are sent over the Control endpoint as a
// Set_Report transfer. The first byte of @p data[] must
// contain the Report ID. For devices which only support a
// single report, this must be set to 0x0. The remaining bytes
// contain the report data. Since the Report ID is mandatory,
// calls to SendOutputReport() will always contain one
// more byte than the report contains. For example, if a hid
// report is 16 bytes long, 17 bytes must be passed to
// SendOutputReport(): the Report ID (or 0x0, for
// devices which do not use numbered reports), followed by the
// report data (16 bytes). In this example, the length passed
// in would be 17.
func (dev *Device) SendOutputReport(b []byte) (int, error) {
// Abort if nothing to write
if len(b) == 0 {
return 0, nil
}
// Abort if device closed in between
dev.lock.Lock()
device := dev.device
dev.lock.Unlock()

if device == nil {
return 0, ErrDeviceClosed
}

// Send the feature report
written := int(C.hid_send_output_report(device, (*C.uchar)(&b[0]), C.size_t(len(b))))
if written == -1 {
// If the write failed, verify if closed or other error
dev.lock.Lock()
device = dev.device
dev.lock.Unlock()

if device == nil {
return 0, ErrDeviceClosed
}
// Device not closed, some other error occurred
message := C.hid_error(device)
if message == nil {
return 0, errors.New("hidapi: unknown failure")
}
failure, _ := wcharTToString(message)
return 0, errors.New("hidapi: " + failure)
}
return written, nil
}

// SetNonblocking sets the device handle to be non-blocking.
//
// In non-blocking mode calls to Read() will return
Expand Down
27 changes: 27 additions & 0 deletions hid_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,30 @@ func (dev *Device) GetContainerId() (*windows.GUID, error) {

return guid, nil
}

const (
INFINITE = -1
)

// SetWriteTimeout sets the timeout for Write operation.
// The default timeout is 1sec for winapi backend.
// In case if 1sec is not enough, on in case of multi-platform development,
// the recommended value is 5sec, e.g. to match (unconfigurable) 5sec timeout
// set for hidraw (linux kernel) implementation.
// When the timeout is set to 0, hid_write function becomes non-blocking and would exit immediately.
// When the timeout is set to INFINITE (-1), the function will not exit,
// until the write operation is performed or an error occurred.
func (dev *Device) SetWriteTimeout(timeout int32) error {
// Abort if device closed in between
dev.lock.Lock()
device := dev.device
dev.lock.Unlock()

if device == nil {
return ErrDeviceClosed
}

C.hid_winapi_set_write_timeout(device, C.ulong(timeout))

return nil
}
2 changes: 1 addition & 1 deletion hidapi/AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Ludovic Rousseau <rousseau@debian.org>:
Correctness fixes

libusb/hidapi Team:
Development/maintainance since June 4th 2019
Development/maintenance since June 4th 2019

For a comprehensive list of contributions, see the commit list at github:
https://github.com/libusb/hidapi/graphs/contributors
Expand Down
4 changes: 2 additions & 2 deletions hidapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

| CI instance | Status |
|----------------------|--------|
| `Linux/macOS/Windows (master)` | [![GitHub Builds](https://github.com/libusb/hidapi/workflows/GitHub%20Builds/badge.svg?branch=master)](https://github.com/libusb/hidapi/actions/workflows/builds.yml?query=branch%3Amaster) |
| `Linux/macOS/Windows (master)` | [![GitHub Builds](https://github.com/libusb/hidapi/actions/workflows/builds.yml/badge.svg?branch=master)](https://github.com/libusb/hidapi/actions/workflows/builds.yml?query=branch%3Amaster) |
| `Windows (master)` | [![Build status](https://ci.appveyor.com/api/projects/status/xfmr5fo8w0re8ded/branch/master?svg=true)](https://ci.appveyor.com/project/libusb/hidapi/branch/master) |
| `BSD, last build (branch/PR)` | [![builds.sr.ht status](https://builds.sr.ht/~z3ntu/hidapi.svg)](https://builds.sr.ht/~z3ntu/hidapi) |
| `Coverity Scan (last)` | ![Coverity Scan](https://scan.coverity.com/projects/583/badge.svg) |
| `Coverity Scan (last)` | [![Coverity Scan](https://scan.coverity.com/projects/583/badge.svg)](https://scan.coverity.com/projects/hidapi) |

HIDAPI is a multi-platform library which allows an application to interface
with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and macOS.
Expand Down
2 changes: 1 addition & 1 deletion hidapi/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.14.0
0.15.0
72 changes: 66 additions & 6 deletions hidapi/hidapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

@ingroup API
*/
#define HID_API_VERSION_MINOR 14
#define HID_API_VERSION_MINOR 15
/** @brief Static/compile-time patch version of the library.

@ingroup API
Expand Down Expand Up @@ -307,9 +307,9 @@ extern "C" {
single report), followed by the report data (16 bytes). In
this example, the length passed in would be 17.

hid_write() will send the data on the first OUT endpoint, if
one exists. If it does not, it will send the data through
the Control Endpoint (Endpoint 0).
hid_write() will send the data on the first interrupt OUT
endpoint, if one exists. If it does not the behaviour is as
@ref hid_send_output_report

@ingroup API
@param dev A device handle returned from hid_open().
Expand Down Expand Up @@ -341,9 +341,11 @@ extern "C" {
@returns
This function returns the actual number of bytes read and
-1 on error.
Call hid_error(dev) to get the failure reason.
Call hid_read_error(dev) to get the failure reason.
If no packet was available to be read within
the timeout period, this function returns 0.

@note This function doesn't change the buffer returned by the hid_error(dev).
*/
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);

Expand All @@ -363,12 +365,36 @@ extern "C" {
@returns
This function returns the actual number of bytes read and
-1 on error.
Call hid_error(dev) to get the failure reason.
Call hid_read_error(dev) to get the failure reason.
If no packet was available to be read and
the handle is in non-blocking mode, this function returns 0.

@note This function doesn't change the buffer returned by the hid_error(dev).
*/
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);

/** @brief Get a string describing the last error which occurred during hid_read/hid_read_timeout.

Since version 0.15.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 15, 0)

This function is intended for logging/debugging purposes.

This function guarantees to never return NULL for a valid @ref dev.
If there was no error in the last call to hid_read/hid_read_error -
the returned string clearly indicates that.

Strings returned from hid_read_error() must not be freed by the user,
i.e. owned by HIDAPI library.
Device-specific error string may remain allocated at most until hid_close() is called.

@ingroup API
@param dev A device handle. Shall never be NULL.

@returns
A string describing the hid_read/hid_read_timeout error (if any).
*/
HID_API_EXPORT const wchar_t* HID_API_CALL hid_read_error(hid_device *dev);

/** @brief Set the device handle to be non-blocking.

In non-blocking mode calls to hid_read() will return
Expand Down Expand Up @@ -445,6 +471,40 @@ extern "C" {
*/
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length);

/** @brief Send a Output report to the device.

Since version 0.15.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 15, 0)

Output reports are sent over the Control endpoint as a
Set_Report transfer. The first byte of @p data[] must
contain the Report ID. For devices which only support a
single report, this must be set to 0x0. The remaining bytes
contain the report data. Since the Report ID is mandatory,
calls to hid_send_output_report() will always contain one
more byte than the report contains. For example, if a hid
report is 16 bytes long, 17 bytes must be passed to
hid_send_output_report(): the Report ID (or 0x0, for
devices which do not use numbered reports), followed by the
report data (16 bytes). In this example, the length passed
in would be 17.

This function sets the return value of hid_error().

@ingroup API
@param dev 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, including
the report number.

@returns
This function returns the actual number of bytes written and
-1 on error.

@see @ref hid_write
*/
int HID_API_EXPORT HID_API_CALL hid_send_output_report(hid_device* dev, const unsigned char* data, size_t length);

/** @brief Get a input report from a HID device.

Since version 0.10.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 10, 0)
Expand Down
Loading