Skip to content

Commit 404a02d

Browse files
committed
Merge branch 'master' into a-bunch-of-sanity-checks
# Conflicts: # mac/hid.c
2 parents b69d7db + 95e6b98 commit 404a02d

File tree

16 files changed

+610
-85
lines changed

16 files changed

+610
-85
lines changed

.github/workflows/docs.yaml

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,12 @@ on:
88

99
jobs:
1010
build:
11-
runs-on: ubuntu-latest
11+
runs-on: ubuntu-24.04
1212
steps:
13+
- name: Install Doxygen
14+
run: sudo apt satisfy "doxygen (>= 1.9.6)"
1315

14-
- name: Install Doxygen static libclang deps
15-
run: sudo apt-get install libclang1-12 libclang-cpp12
16-
17-
- name: Install Doxygen from SF binary archives
18-
env:
19-
DOXYGEN_VERSION: '1.9.6'
20-
run: |
21-
mkdir .doxygen && cd .doxygen
22-
curl -L https://sourceforge.net/projects/doxygen/files/rel-$DOXYGEN_VERSION/doxygen-$DOXYGEN_VERSION.linux.bin.tar.gz > doxygen.tar.gz
23-
gunzip doxygen.tar.gz
24-
tar xf doxygen.tar
25-
cd doxygen-$DOXYGEN_VERSION
26-
sudo make install
27-
28-
- uses: actions/checkout@v3
16+
- uses: actions/checkout@v4
2917

3018
- run: doxygen
3119
working-directory: doxygen
@@ -37,7 +25,7 @@ jobs:
3725
path: ${{ github.workspace }}/doxygen/html
3826

3927
deploy-docs:
40-
runs-on: ubuntu-latest
28+
runs-on: ubuntu-24.04
4129
needs: [build]
4230
if: github.ref_type == 'branch' && github.ref_name == 'master'
4331
concurrency:
@@ -51,7 +39,7 @@ jobs:
5139
path: docs
5240

5341
- name: upload to github pages
54-
uses: peaceiris/actions-gh-pages@v3
42+
uses: peaceiris/actions-gh-pages@v4
5543
with:
5644
github_token: ${{ secrets.GITHUB_TOKEN }}
5745
publish_dir: ./docs

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
@@ -1607,11 +1607,20 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
16071607
return bytes_read;
16081608
}
16091609

1610+
16101611
int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
16111612
{
16121613
return hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0);
16131614
}
16141615

1616+
1617+
HID_API_EXPORT const wchar_t * HID_API_CALL hid_read_error(hid_device *dev)
1618+
{
1619+
(void)dev;
1620+
return L"hid_read_error is not implemented yet";
1621+
}
1622+
1623+
16151624
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
16161625
{
16171626
if (!dev)

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;
@@ -1151,7 +1153,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
11511153
}
11521154

11531155
/* Set device error to none */
1154-
register_device_error(dev, NULL);
1156+
register_error_str(&dev->last_read_error_str, NULL);
11551157

11561158
int bytes_read;
11571159

@@ -1175,15 +1177,15 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
11751177
}
11761178
if (ret == -1) {
11771179
/* Error */
1178-
register_device_error(dev, strerror(errno));
1180+
register_error_str(&dev->last_read_error_str, strerror(errno));
11791181
return ret;
11801182
}
11811183
else {
11821184
/* Check for errors on the file descriptor. This will
11831185
indicate a device disconnection. */
11841186
if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
11851187
// We cannot use strerror() here as no -1 was returned from poll().
1186-
register_device_error(dev, "hid_read_timeout: unexpected poll error (device disconnected)");
1188+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: unexpected poll error (device disconnected)");
11871189
return -1;
11881190
}
11891191
}
@@ -1194,7 +1196,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
11941196
if (errno == EAGAIN || errno == EINPROGRESS)
11951197
bytes_read = 0;
11961198
else
1197-
register_device_error(dev, strerror(errno));
1199+
register_error_str(&dev->last_read_error_str, strerror(errno));
11981200
}
11991201

12001202
return bytes_read;
@@ -1210,6 +1212,13 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
12101212
return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
12111213
}
12121214

1215+
HID_API_EXPORT const wchar_t * HID_API_CALL hid_read_error(hid_device *dev)
1216+
{
1217+
if (dev->last_read_error_str == NULL)
1218+
return L"Success";
1219+
return dev->last_read_error_str;
1220+
}
1221+
12131222
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
12141223
{
12151224
if (!dev) {
@@ -1305,8 +1314,8 @@ void HID_API_EXPORT hid_close(hid_device *dev)
13051314

13061315
close(dev->device_handle);
13071316

1308-
/* Free the device error message */
1309-
register_device_error(dev, NULL);
1317+
free(dev->last_error_str);
1318+
free(dev->last_read_error_str);
13101319

13111320
hid_free_enumeration(dev->device_info);
13121321

mac/CMakeLists.txt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,27 @@ set_target_properties(hidapi_darwin
2121
OUTPUT_NAME "hidapi"
2222
VERSION ${PROJECT_VERSION}
2323
SOVERSION ${PROJECT_VERSION_MAJOR}
24-
MACHO_COMPATIBILITY_VERSION ${PROJECT_VERSION_MAJOR}
2524
FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR}
2625
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
2726
)
2827

28+
if(NOT CMAKE_VERSION VERSION_LESS 3.17)
29+
option(HIDAPI_USE_LEGACY_COMPATIBILITY_VERSION "Legacy Autotools build system hard-coded 1.0.0 for compatibility version" FALSE)
30+
if(HIDAPI_USE_LEGACY_COMPATIBILITY_VERSION)
31+
# TODO: v1: remove this workaround
32+
set_target_properties(hidapi_darwin
33+
PROPERTIES
34+
MACHO_COMPATIBILITY_VERSION "1.0.0"
35+
MACHO_CURRENT_VERSION "1.0.0"
36+
)
37+
else()
38+
set_target_properties(hidapi_darwin
39+
PROPERTIES
40+
MACHO_COMPATIBILITY_VERSION ${PROJECT_VERSION_MAJOR}
41+
)
42+
endif()
43+
endif()
44+
2945
# compatibility with find_package()
3046
add_library(hidapi::darwin ALIAS hidapi_darwin)
3147
# compatibility with raw library link

mac/hid.c

Lines changed: 16 additions & 8 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);
@@ -195,6 +197,8 @@ static void free_hid_device(hid_device *dev)
195197
if (dev->source)
196198
CFRelease(dev->source);
197199
free(dev->input_report_buf);
200+
free(dev->last_error_str);
201+
free(dev->last_read_error_str);
198202
hid_free_enumeration(dev->device_info);
199203

200204
/* Clean up the thread objects */
@@ -1278,10 +1282,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
12781282
{
12791283
int bytes_read = -1;
12801284

1281-
if (!dev) {
1282-
register_global_error("Device is NULL");
1283-
return bytes_read;
1284-
}
1285+
register_error_str(&dev->last_read_error_str, NULL);
12851286

12861287
/* Lock the access to the report list. */
12871288
pthread_mutex_lock(&dev->mutex);
@@ -1296,7 +1297,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
12961297
/* Return if the device has been disconnected. */
12971298
if (dev->disconnected) {
12981299
bytes_read = -1;
1299-
register_device_error(dev, "hid_read_timeout: device disconnected");
1300+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: device disconnected");
13001301
goto ret;
13011302
}
13021303

@@ -1305,7 +1306,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13051306
has been an error. An error code of -1 should
13061307
be returned. */
13071308
bytes_read = -1;
1308-
register_device_error(dev, "hid_read_timeout: thread shutdown");
1309+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: thread shutdown");
13091310
goto ret;
13101311
}
13111312

@@ -1319,7 +1320,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13191320
bytes_read = return_data(dev, data, length);
13201321
else {
13211322
/* There was an error, or a device disconnection. */
1322-
register_device_error(dev, "hid_read_timeout: error waiting for more data");
1323+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: error waiting for more data");
13231324
bytes_read = -1;
13241325
}
13251326
}
@@ -1343,7 +1344,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
13431344
} else if (res == ETIMEDOUT) {
13441345
bytes_read = 0;
13451346
} else {
1346-
register_device_error(dev, "hid_read_timeout: error waiting for more data");
1347+
register_error_str(&dev->last_read_error_str, "hid_read_timeout: error waiting for more data");
13471348
bytes_read = -1;
13481349
}
13491350
}
@@ -1368,6 +1369,13 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
13681369
return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
13691370
}
13701371

1372+
HID_API_EXPORT const wchar_t * HID_API_CALL hid_read_error(hid_device *dev)
1373+
{
1374+
if (dev->last_read_error_str == NULL)
1375+
return L"Success";
1376+
return dev->last_read_error_str;
1377+
}
1378+
13711379
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
13721380
{
13731381
if (!dev) {

0 commit comments

Comments
 (0)