Skip to content

Commit 95e6b98

Browse files
authored
Add hid_read_error (#721)
hid_read_error is a separate error function, that returns error status of hid_read/hid_read_timeout. hid_read/hid_read_timeout is no longer changes internal buffer used by hid_error and it makes it safe to use hid_read/hid_read_timeout from a separa thread, concurently with other device functions.
1 parent 122ecb0 commit 95e6b98

File tree

7 files changed

+122
-22
lines changed

7 files changed

+122
-22
lines changed

hidapi/hidapi.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,11 @@ extern "C" {
341341
@returns
342342
This function returns the actual number of bytes read and
343343
-1 on error.
344-
Call hid_error(dev) to get the failure reason.
344+
Call hid_read_error(dev) to get the failure reason.
345345
If no packet was available to be read within
346346
the timeout period, this function returns 0.
347+
348+
@note This function doesn't change the buffer returned by the hid_error(dev).
347349
*/
348350
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
349351

@@ -363,12 +365,40 @@ extern "C" {
363365
@returns
364366
This function returns the actual number of bytes read and
365367
-1 on error.
366-
Call hid_error(dev) to get the failure reason.
368+
Call hid_read_error(dev) to get the failure reason.
367369
If no packet was available to be read and
368370
the handle is in non-blocking mode, this function returns 0.
371+
372+
@note This function doesn't change the buffer returned by the hid_error(dev).
369373
*/
370374
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
371375

376+
/** @brief Get a string describing the last error which occurred during hid_read/hid_read_timeout.
377+
378+
Since version 0.15.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 15, 0)
379+
380+
This function is intended for logging/debugging purposes.
381+
382+
This function guarantees to never return NULL.
383+
If there was no error in the last call to hid_read/hid_read_error -
384+
the returned string clearly indicates that.
385+
386+
Any HIDAPI function that can explicitly indicate an execution failure
387+
(e.g. by an error code, or by returning NULL) - may set the error string,
388+
to be returned by this function.
389+
390+
Strings returned from hid_read_error() must not be freed by the user,
391+
i.e. owned by HIDAPI library.
392+
Device-specific error string may remain allocated at most until hid_close() is called.
393+
394+
@ingroup API
395+
@param dev A device handle. Shall never be NULL.
396+
397+
@returns
398+
A string describing the hid_read/hid_read_timeout error (if any).
399+
*/
400+
HID_API_EXPORT const wchar_t* HID_API_CALL hid_read_error(hid_device *dev);
401+
372402
/** @brief Set the device handle to be non-blocking.
373403
374404
In non-blocking mode calls to hid_read() will return

hidtest/test.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,13 @@ int main(int argc, char* argv[])
245245
// Try to read from the device. There should be no
246246
// data here, but execution should not block.
247247
res = hid_read(handle, buf, 17);
248+
if (res < 0) {
249+
#if HID_API_VERSION >= HID_API_MAKE_VERSION(0, 15, 0)
250+
printf("Unable to read from device: %ls\n", hid_read_error(handle));
251+
#else
252+
printf("Unable to read from device: %ls\n", hid_error(handle));
253+
#endif
254+
}
248255

249256
// Send a Feature Report to the device
250257
buf[0] = 0x2;
@@ -254,7 +261,7 @@ int main(int argc, char* argv[])
254261
buf[4] = 0x00;
255262
res = hid_send_feature_report(handle, buf, 17);
256263
if (res < 0) {
257-
printf("Unable to send a feature report.\n");
264+
printf("Unable to send a feature report: %ls\n", hid_error(handle));
258265
}
259266

260267
memset(buf,0,sizeof(buf));

libusb/hid.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,11 +1557,20 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
15571557
return bytes_read;
15581558
}
15591559

1560+
15601561
int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
15611562
{
15621563
return hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0);
15631564
}
15641565

1566+
1567+
HID_API_EXPORT const wchar_t * HID_API_CALL hid_read_error(hid_device *dev)
1568+
{
1569+
(void)dev;
1570+
return L"hid_read_error is not implemented yet";
1571+
}
1572+
1573+
15651574
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
15661575
{
15671576
dev->blocking = !nonblock;

linux/hid.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct hid_device_ {
7575
int device_handle;
7676
int blocking;
7777
wchar_t *last_error_str;
78+
wchar_t *last_read_error_str;
7879
struct hid_device_info* device_info;
7980
};
8081

@@ -97,6 +98,7 @@ static hid_device *new_hid_device(void)
9798
dev->device_handle = -1;
9899
dev->blocking = 1;
99100
dev->last_error_str = NULL;
101+
dev->last_read_error_str = NULL;
100102
dev->device_info = NULL;
101103

102104
return dev;
@@ -1108,7 +1110,7 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t
11081110
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
11091111
{
11101112
/* Set device error to none */
1111-
register_device_error(dev, NULL);
1113+
register_error_str(&dev->last_read_error_str, NULL);
11121114

11131115
int bytes_read;
11141116

@@ -1132,15 +1134,15 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
11321134
}
11331135
if (ret == -1) {
11341136
/* Error */
1135-
register_device_error(dev, strerror(errno));
1137+
register_error_str(&dev->last_read_error_str, strerror(errno));
11361138
return ret;
11371139
}
11381140
else {
11391141
/* Check for errors on the file descriptor. This will
11401142
indicate a device disconnection. */
11411143
if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
11421144
// We cannot use strerror() here as no -1 was returned from poll().
1143-
register_device_error(dev, "hid_read_timeout: unexpected poll error (device disconnected)");
1145+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: unexpected poll error (device disconnected)");
11441146
return -1;
11451147
}
11461148
}
@@ -1151,7 +1153,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
11511153
if (errno == EAGAIN || errno == EINPROGRESS)
11521154
bytes_read = 0;
11531155
else
1154-
register_device_error(dev, strerror(errno));
1156+
register_error_str(&dev->last_read_error_str, strerror(errno));
11551157
}
11561158

11571159
return bytes_read;
@@ -1162,6 +1164,13 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
11621164
return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
11631165
}
11641166

1167+
HID_API_EXPORT const wchar_t * HID_API_CALL hid_read_error(hid_device *dev)
1168+
{
1169+
if (dev->last_read_error_str == NULL)
1170+
return L"Success";
1171+
return dev->last_read_error_str;
1172+
}
1173+
11651174
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
11661175
{
11671176
/* Do all non-blocking in userspace using poll(), since it looks
@@ -1232,8 +1241,8 @@ void HID_API_EXPORT hid_close(hid_device *dev)
12321241

12331242
close(dev->device_handle);
12341243

1235-
/* Free the device error message */
1236-
register_device_error(dev, NULL);
1244+
free(dev->last_error_str);
1245+
free(dev->last_read_error_str);
12371246

12381247
hid_free_enumeration(dev->device_info);
12391248

mac/hid.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ struct hid_device_ {
142142
pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */
143143
int shutdown_thread;
144144
wchar_t *last_error_str;
145+
wchar_t *last_read_error_str;
145146
};
146147

147148
static hid_device *new_hid_device(void)
@@ -163,6 +164,7 @@ static hid_device *new_hid_device(void)
163164
dev->device_info = NULL;
164165
dev->shutdown_thread = 0;
165166
dev->last_error_str = NULL;
167+
dev->last_read_error_str = NULL;
166168

167169
/* Thread objects */
168170
pthread_mutex_init(&dev->mutex, NULL);
@@ -196,6 +198,7 @@ static void free_hid_device(hid_device *dev)
196198
CFRelease(dev->source);
197199
free(dev->input_report_buf);
198200
free(dev->last_error_str);
201+
free(dev->last_read_error_str);
199202
hid_free_enumeration(dev->device_info);
200203

201204
/* Clean up the thread objects */
@@ -1244,6 +1247,8 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
12441247
{
12451248
int bytes_read = -1;
12461249

1250+
register_error_str(&dev->last_read_error_str, NULL);
1251+
12471252
/* Lock the access to the report list. */
12481253
pthread_mutex_lock(&dev->mutex);
12491254

@@ -1257,7 +1262,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
12571262
/* Return if the device has been disconnected. */
12581263
if (dev->disconnected) {
12591264
bytes_read = -1;
1260-
register_device_error(dev, "hid_read_timeout: device disconnected");
1265+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: device disconnected");
12611266
goto ret;
12621267
}
12631268

@@ -1266,7 +1271,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
12661271
has been an error. An error code of -1 should
12671272
be returned. */
12681273
bytes_read = -1;
1269-
register_device_error(dev, "hid_read_timeout: thread shutdown");
1274+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: thread shutdown");
12701275
goto ret;
12711276
}
12721277

@@ -1280,7 +1285,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
12801285
bytes_read = return_data(dev, data, length);
12811286
else {
12821287
/* There was an error, or a device disconnection. */
1283-
register_device_error(dev, "hid_read_timeout: error waiting for more data");
1288+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: error waiting for more data");
12841289
bytes_read = -1;
12851290
}
12861291
}
@@ -1304,7 +1309,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13041309
} else if (res == ETIMEDOUT) {
13051310
bytes_read = 0;
13061311
} else {
1307-
register_device_error(dev, "hid_read_timeout: error waiting for more data");
1312+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: error waiting for more data");
13081313
bytes_read = -1;
13091314
}
13101315
}
@@ -1324,6 +1329,13 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
13241329
return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
13251330
}
13261331

1332+
HID_API_EXPORT const wchar_t * HID_API_CALL hid_read_error(hid_device *dev)
1333+
{
1334+
if (dev->last_read_error_str == NULL)
1335+
return L"Success";
1336+
return dev->last_read_error_str;
1337+
}
1338+
13271339
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
13281340
{
13291341
/* All Nonblocking operation is handled by the library. */

netbsd/hid.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct hid_device_ {
4545
int device_handle;
4646
int blocking;
4747
wchar_t *last_error_str;
48+
wchar_t *last_read_error_str;
4849
struct hid_device_info *device_info;
4950
size_t poll_handles_length;
5051
struct pollfd poll_handles[256];
@@ -143,6 +144,18 @@ static void register_device_error_format(hid_device *dev, const char *format, ..
143144
va_end(args);
144145
}
145146

147+
static void register_device_read_error(hid_device *dev, const char *msg)
148+
{
149+
register_error_str(&dev->last_read_error_str, msg);
150+
}
151+
152+
static void register_device_read_error_format(hid_device *dev, const char *format, ...)
153+
{
154+
va_list args;
155+
va_start(args, format);
156+
register_error_str_vformat(&dev->last_read_error_str, format, args);
157+
va_end(args);
158+
}
146159

147160
/*
148161
* Gets the size of the HID item at the given position
@@ -878,9 +891,11 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
878891
struct pollfd *ph;
879892
ssize_t n;
880893

894+
register_device_read_error(dev, NULL);
895+
881896
res = poll(dev->poll_handles, dev->poll_handles_length, milliseconds);
882897
if (res == -1) {
883-
register_device_error_format(dev, "error while polling: %s", strerror(errno));
898+
register_device_read_error_format(dev, "error while polling: %s", strerror(errno));
884899
return -1;
885900
}
886901

@@ -891,7 +906,7 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
891906
ph = &dev->poll_handles[i];
892907

893908
if (ph->revents & (POLLERR | POLLHUP | POLLNVAL)) {
894-
register_device_error(dev, "device IO error while polling");
909+
register_device_read_error(dev, "device IO error while polling");
895910
return -1;
896911
}
897912

@@ -907,7 +922,7 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
907922
if (errno == EAGAIN || errno == EINPROGRESS)
908923
n = 0;
909924
else
910-
register_device_error_format(dev, "error while reading: %s", strerror(errno));
925+
register_device_read_error_format(dev, "error while reading: %s", strerror(errno));
911926
}
912927

913928
return n;
@@ -918,6 +933,13 @@ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, s
918933
return hid_read_timeout(dev, data, length, (dev->blocking) ? -1 : 0);
919934
}
920935

936+
HID_API_EXPORT const wchar_t* HID_API_CALL hid_read_error(hid_device *dev)
937+
{
938+
if (dev->last_read_error_str == NULL)
939+
return L"Success";
940+
return dev->last_read_error_str;
941+
}
942+
921943
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
922944
{
923945
dev->blocking = !nonblock;
@@ -949,8 +971,8 @@ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
949971
if (!dev)
950972
return;
951973

952-
/* Free the device error message */
953-
register_device_error(dev, NULL);
974+
free(dev->last_error_str);
975+
free(dev->last_read_error_str);
954976

955977
hid_free_enumeration(dev->device_info);
956978

0 commit comments

Comments
 (0)