From 02a882c89076a626e689c7dd127076fa5ede36d9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 8 Jul 2013 10:59:10 +0200 Subject: [PATCH 01/27] libusb: Properly wait for transfer cancellation on read_thread() exit While triaging libusb bugs, I took an indepth look at: https://github.com/libusbx/libusbx/issues/25 This has lead me to the conclusion that there are 2 issues with hidapi's libusb code wrt waiting for the transfer cancellation on read_thread() exit: 1) There is a race where hid_close() can successfully cancel the transfer after a read_callback() has submitted it but before read_thread() checks shutdown_thread. If this race is hit, then the libusb_cancel_transfer() in read_thread() will fail, causing read_thread() to not call libusb_handle_events() to complete the cancelled transfer. hid_close() will then free the transfer, and if later on libusb_handle_events() gets called on the same context, it will try to complete the now freed transfer. This is what I believe leads to the segfault described in https://github.com/libusbx/libusbx/issues/25 2) hidapi uses one read_thread() per hid_device, so if there are multiple hid_devices then there are multiple threads calling libusb_handle_events(), in this case there is no guarantee that a single libusb_handle_events() call will successfully lead to the cancelled transfer being completed. If the transfer completion is already handled by another read_thread() and there are no other events, then the libusb_handle_events() call will hang, and thus the pthread_join() and thus hidapi_close() will hang. As number 2 is a generic problem found in more libusb apps, libusb has gotten a new API called libusb_handle_events_completed(), which takes an extra pointer to an int, whose contents must be set to nonzero on completion by the callback, which allows waiting for the completion of a specific transfer in a race-free manner. This patch switches the waiting for the transfer's final completion to using libusb_handle_events_completed(), thereby fixing both issues. Note the while is necessary since libusb_handle_events_completed(), like libusb_handle_events(), will return as soon as it has handled *any* event. The difference with libusb_handle_events_completed() is that once it has all the necessary internal libusb locks, it checks the contents of the completed parameter, and will bail if that has become nonzero without waiting for further events. Signed-off-by: Hans de Goede --- configure.ac | 2 +- libusb/hid.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 3533bef7..8449b401 100644 --- a/configure.ac +++ b/configure.ac @@ -68,7 +68,7 @@ case $host in # HIDAPI/libusb libs AC_CHECK_LIB([rt], [clock_gettime], [LIBS_LIBUSB_PRIVATE+=" -lrt"], [hidapi_lib_error librt]) - PKG_CHECK_MODULES([libusb], [libusb-1.0], true, [hidapi_lib_error libusb-1.0]) + PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0]) LIBS_LIBUSB_PRIVATE+=" $libusb_LIBS" CFLAGS_LIBUSB+=" $libusb_CFLAGS" ;; diff --git a/libusb/hid.c b/libusb/hid.c index 94c1b3b6..dcf9d80e 100644 --- a/libusb/hid.c +++ b/libusb/hid.c @@ -105,6 +105,7 @@ struct hid_device_ { pthread_cond_t condition; pthread_barrier_t barrier; /* Ensures correct startup sequence */ int shutdown_thread; + int cancelled; struct libusb_transfer *transfer; /* List of received input reports. */ @@ -683,10 +684,12 @@ static void read_callback(struct libusb_transfer *transfer) } else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { dev->shutdown_thread = 1; + dev->cancelled = 1; return; } else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { dev->shutdown_thread = 1; + dev->cancelled = 1; return; } else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) { @@ -701,6 +704,7 @@ static void read_callback(struct libusb_transfer *transfer) if (res != 0) { LOG("Unable to submit URB. libusb error code: %d\n", res); dev->shutdown_thread = 1; + dev->cancelled = 1; } } @@ -750,10 +754,10 @@ static void *read_thread(void *param) /* Cancel any transfer that may be pending. This call will fail if no transfers are pending, but that's OK. */ - if (libusb_cancel_transfer(dev->transfer) == 0) { - /* The transfer was cancelled, so wait for its completion. */ - libusb_handle_events(usb_context); - } + libusb_cancel_transfer(dev->transfer); + + while (!dev->cancelled) + libusb_handle_events_completed(usb_context, &dev->cancelled); /* Now that the read thread is stopping, Wake any threads which are waiting on data (in hid_read_timeout()). Do this under a mutex to From 4e6e9ffe864e1e7446296294c2a329bd91076529 Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Tue, 6 Aug 2013 21:05:17 +0100 Subject: [PATCH 02/27] gitignore: add config.* to .gitignore This makes HIDAPI less noisy when used a git submodule. Signed-off-by: Spencer Oliver --- .gitignore | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index bc0410f0..b43ca58c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,7 @@ Makefile.in aclocal.m4 autom4te.cache/ -config.guess -config.h.in -config.sub +config.* configure depcomp install-sh @@ -18,8 +16,5 @@ testgui/Makefile.in windows/Makefile.in Makefile -config.h -config.log -config.status stamp-h1 libtool From 1ec76ad9bda77574fc276d40e4f978c898de1e89 Mon Sep 17 00:00:00 2001 From: Alan Ott Date: Mon, 9 Sep 2013 00:18:00 -0400 Subject: [PATCH 03/27] README: Add build dependencies Some build system dependencies were missing from the documentation. --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 9297fb6e..b4e7c0e0 100644 --- a/README.txt +++ b/README.txt @@ -154,7 +154,7 @@ Prerequisites: If you downloaded the source directly from the git repository (using git clone), you'll need Autotools: - sudo apt-get install autotools-dev + sudo apt-get install autotools-dev autoconf automake libtool FreeBSD: --------- From a88c7244d632ed238b829968be9b765605b53c34 Mon Sep 17 00:00:00 2001 From: Alan Ott Date: Mon, 9 Sep 2013 09:39:31 -0400 Subject: [PATCH 04/27] mac: Fix incorrect device list after device removal On Mac OS X 10.8.x (Mountain Lion), if a device is connected, opened, then closed, then unplugged, subsequent calls to hid_enumerate() will still list the device (even though it's been unplugged). If the device is plugged in again, a second instance will show up in the list and often it will be impossible to open either. Github user TamToucan figured out that in hid_enumerate() if a call is made to IOHIDManagerSetDeviceMatching() before the call to IOHIDManagerCopyDevices() that this will clear the problem. Thanks to TamToucan for figuring this out. --- mac/hid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mac/hid.c b/mac/hid.c index 13109239..6768f9c2 100644 --- a/mac/hid.c +++ b/mac/hid.c @@ -420,6 +420,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, process_pending_events(); /* Get a list of the Devices */ + IOHIDManagerSetDeviceMatching(hid_mgr, NULL); CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); /* Convert the list into a C array so we can iterate easily. */ From 24e9658a3102eaba74d0b60d6150787c4c45ec19 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Mon, 9 Sep 2013 21:38:30 +0200 Subject: [PATCH 05/27] add a test program to parse the hid descriptor and data --- hidtest/hidtest.cpp | 576 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 516 insertions(+), 60 deletions(-) diff --git a/hidtest/hidtest.cpp b/hidtest/hidtest.cpp index 7027a101..03b242a8 100644 --- a/hidtest/hidtest.cpp +++ b/hidtest/hidtest.cpp @@ -27,14 +27,165 @@ #include #endif + +//// ---------- HID descriptor parser + +#define MAX_DESCRIPTOR 4096 + + +// main items +#define HID_INPUT 0x80 +#define HID_OUTPUT 0x90 +#define HID_COLLECTION 0xA0 +#define HID_FEATURE 0xB0 +// #define HID_COLLECTION 0xa1 +#define HID_END_COLLECTION 0xC0 + +// HID Report Items from HID 1.11 Section 6.2.2 +#define HID_USAGE_PAGE 0x04 +// #define HID_USAGE_PAGE 0x05 +// #define HID_USAGE_PAGE_EXT 0x06 + +#define HID_USAGE 0x08 +// #define HID_USAGE 0x09 +// #define HID_USAGE_EXT 0x0a + +#define HID_USAGE_MIN 0x18 +// #define HID_USAGE_MIN 0x19 +#define HID_USAGE_MAX 0x28 +// #define HID_USAGE_MAX 0x29 + +#define HID_DESIGNATOR_INDEX 0x38 +#define HID_DESIGNATOR_MIN 0x48 +#define HID_DESIGNATOR_MAX 0x58 + +#define HID_STRING_INDEX 0x78 +#define HID_STRING_MIN 0x88 +#define HID_STRING_MAX 0x98 + +#define HID_DELIMITER 0xA8 + +#define HID_LOGICAL_MIN 0x14 +// #define HID_LOGICAL_MIN 0x15 +// #define HID_LOGICAL_MIN_2 0x16 +#define HID_LOGICAL_MAX 0x24 +// #define HID_LOGICAL_MAX 0x25 +// #define HID_LOGICAL_MAX_2 0x26 + +#define HID_PHYSICAL_MIN 0x34 +// #define HID_PHYSICAL_MIN 0x35 +// #define HID_PHYSICAL_MIN_2 0x36 +// #define HID_PHYSICAL_MIN_3 0x37 +#define HID_PHYSICAL_MAX 0x44 +// #define HID_PHYSICAL_MAX 0x45 +// #define HID_PHYSICAL_MAX_2 0x46 + +#define HID_UNIT_EXPONENT 0x54 +// #define HID_UNIT 0x55 +#define HID_UNIT 0x64 +// #define HID_UNIT 0x65 + +#define HID_REPORT_SIZE 0x74 +// #define HID_REPORT_SIZE 0x75 +#define HID_REPORT_ID 0x84 + +#define HID_REPORT_COUNT 0x94 +// #define HID_REPORT_COUNT 0x95 + +#define HID_PUSH 0xA4 +#define HID_POP 0xB4 + +#define HID_RESERVED 0xC4 // above this it is all reserved + + +// HID Report Usage Pages from HID Usage Tables 1.12 Section 3, Table 1 +#define HID_USAGE_PAGE_GENERICDESKTOP 0x01 +#define HID_USAGE_PAGE_KEY_CODES 0x07 +#define HID_USAGE_PAGE_LEDS 0x08 +#define HID_USAGE_PAGE_BUTTONS 0x09 + +// HID Report Usages from HID Usage Tables 1.12 Section 4, Table 6 +#define HID_USAGE_POINTER 0x01 +#define HID_USAGE_MOUSE 0x02 +#define HID_USAGE_JOYSTICK 0x04 +#define HID_USAGE_KEYBOARD 0x06 +#define HID_USAGE_X 0x30 +#define HID_USAGE_Y 0x31 +#define HID_USAGE_Z 0x32 +#define HID_USAGE_RX 0x33 +#define HID_USAGE_RY 0x34 +#define HID_USAGE_RZ 0x35 +#define HID_USAGE_SLIDER 0x36 +#define HID_USAGE_DIAL 0x37 +#define HID_USAGE_WHEEL 0x38 + + +// HID Report Collection Types from HID 1.12 6.2.2.6 +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 + +// HID Input/Output/Feature Item Data (attributes) from HID 1.11 6.2.2.5 +/// more like flags +#define HID_ITEM_CONSTANT 0x1 +#define HID_ITEM_VARIABLE 0x2 +#define HID_ITEM_RELATIVE 0x4 +#define HID_ITEM_WRAP 0x8 +#define HID_ITEM_LINEAR 0x10 +#define HID_ITEM_PREFERRED 0x20 +#define HID_ITEM_NULL 0x40 +#define HID_ITEM_BITFIELD 0x80 + +// Report Types from HID 1.11 Section 7.2.1 +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + +struct hid_device_descriptor { + int num_elements; +// int usage_page; +// int usage; + /** Pointer to the first element */ + struct hid_device_element *first; +}; + +struct hid_device_element { + int index; + + int type; // button/axis + int vartype; // abs/relative + int usage_page; // usage page + int usage; // some kind of index (as from descriptor) + + int logical_min; + int logical_max; + + int phys_min; + int phys_max; + + int resolution; // in bits + + int value; + + /** Pointer to the next element */ + struct hid_device_element *next; +}; + +struct hid_device_descriptor *descriptor; + +#define BITMASK1(n) ((1ULL << (n)) - 1ULL) + int main(int argc, char* argv[]) { int res; unsigned char buf[256]; + unsigned char descr_buf[MAX_DESCRIPTOR]; #define MAX_STR 255 wchar_t wstr[MAX_STR]; hid_device *handle; int i; + + descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); + descriptor->num_elements = 0; #ifdef WIN32 UNREFERENCED_PARAMETER(argc); @@ -69,7 +220,11 @@ int main(int argc, char* argv[]) // Open the device using the VID, PID, // and optionally the Serial number. ////handle = hid_open(0x4d8, 0x3f, L"12345"); - handle = hid_open(0x4d8, 0x3f, NULL); +// handle = hid_open(0x4d8, 0x3f, NULL); + // mouse: +// handle = hid_open(0x1241, 0x1166, NULL); + // run'n'drive + handle = hid_open(0x044f, 0xd003, NULL); if (!handle) { printf("unable to open device\n"); return 1; @@ -104,82 +259,383 @@ int main(int argc, char* argv[]) printf("Unable to read indexed string 1\n"); printf("Indexed String 1: %ls\n", wstr); - // Set the hid_read() function to be non-blocking. - hid_set_nonblocking(handle, 1); - - // Try to read from the device. There shoud be no - // data here, but execution should not block. - res = hid_read(handle, buf, 17); - - // Send a Feature Report to the device - buf[0] = 0x2; - buf[1] = 0xa0; - buf[2] = 0x0a; - buf[3] = 0x00; - buf[4] = 0x00; - res = hid_send_feature_report(handle, buf, 17); - if (res < 0) { - printf("Unable to send a feature report.\n"); - } - - memset(buf,0,sizeof(buf)); - // Read a Feature Report from the device - buf[0] = 0x2; - res = hid_get_feature_report(handle, buf, sizeof(buf)); - if (res < 0) { - printf("Unable to get a feature report.\n"); - printf("%ls", hid_error(handle)); - } - else { - // Print out the returned buffer. - printf("Feature Report\n "); - for (i = 0; i < res; i++) - printf("%02hhx ", buf[i]); - printf("\n"); + //// PARSING THE DESCRIPTOR + res = hid_get_report_descriptor( handle, descr_buf, MAX_DESCRIPTOR ); + if (res < 0) + printf("Unable to read report descriptor\n"); + printf("Data read: %i\n ", res); + // Print out the returned buffer. + + struct hid_device_element * prev_element; + int current_usage_page; + int current_usage; + int current_usages[256]; + int current_usage_index = 0; + int current_usage_min = -1; + int current_usage_max = -1; + int current_logical_min; + int current_logical_max; + int current_physical_min; + int current_physical_max; + int current_report_count; + int current_report_id; + int current_report_size; + char current_input; + char current_output; + int collection_nesting = 0; + + int next_byte_type = -1; + int next_byte_size = 0; + int next_val = 0; + + int toadd = 0; + int byte_count = 0; + +// for (i = 0; i < res; i++){ +// printf("\n%02hhx ", descr_buf[i]); +// } + for (i = 0; i < res; i++){ + printf("\n%02hhx ", descr_buf[i]); + printf("\tbyte_type %i, %i, %i \t", next_byte_type, next_byte_size, next_val); + if ( next_byte_type != -1 ){ + toadd = descr_buf[i]; + for ( int j=0; jindex = descriptor->num_elements; + new_element->type = current_input; // & HID_ITEM_VARIABLE); + // new_element->vartype = (current_input & HID_ITEM_RELATIVE); + new_element->usage_page = current_usage_page; + if ( current_usage_min != -1 ){ + new_element->usage = current_usage_min + j; + } else { + new_element->usage = current_usages[j]; + } + new_element->logical_min = current_logical_min; + new_element->logical_max = current_logical_max; + new_element->phys_min = current_physical_min; + new_element->phys_max = current_physical_max; + new_element->resolution = current_report_size; + new_element->value = 0; + if ( descriptor->num_elements == 0 ){ + descriptor->first = new_element; + } else { + prev_element->next = new_element; + } + descriptor->num_elements++; + prev_element = new_element; + } + current_usage_min = -1; + current_usage_max = -1; + current_usage_index = 0; + break; + case HID_OUTPUT: + current_output = next_val; + printf("output: %i", current_output); + printf("should create output element"); + // next_byte_type = -1; + current_usage_min = -1; + current_usage_max = -1; + current_usage_index = 0; + break; + case HID_FEATURE: + // current_output = next_val; + printf("feature: %i", next_val); + printf("should create feature element"); + // next_byte_type = -1; + current_usage_min = -1; + current_usage_max = -1; + current_usage_index = 0; + break; + default: + if ( next_byte_type >= HID_RESERVED ){ + printf("reserved bytes 0x%02hhx, %i", next_byte_type, next_val ); + } else { + printf("undefined byte type 0x%02hhx, %i", next_byte_type, next_val ); + } + } + next_byte_type = -1; + } + } else { +// printf("\n"); + printf("\tsetting next byte type: %i, 0x%02hhx ", descr_buf[i], descr_buf[i] ); + if ( descr_buf[i] == HID_END_COLLECTION ){ // JUST one byte + collection_nesting--; + printf("\tend collection: %i, %i\n", collection_nesting, descr_buf[i] ); + } else { + byte_count = 0; + toadd = 0; + next_val = 0; + next_byte_type = descr_buf[i] & 0xFC; + next_byte_size = descr_buf[i] & 0x03; + if ( next_byte_size == 3 ){ + next_byte_size = 4; + } + printf("\t next byte type: 0x%02hhx, %i ", next_byte_type, next_byte_size ); + } + } } + printf("\n"); + printf("number of elements, %i\n", descriptor->num_elements ); + + // Set the hid_read() function to be non-blocking. + hid_set_nonblocking(handle, 1); +// +// // Try to read from the device. There shoud be no +// // data here, but execution should not block. +// res = hid_read(handle, buf, 17); +// +// // Send a Feature Report to the device +// buf[0] = 0x2; +// buf[1] = 0xa0; +// buf[2] = 0x0a; +// buf[3] = 0x00; +// buf[4] = 0x00; +// res = hid_send_feature_report(handle, buf, 17); +// if (res < 0) { +// printf("Unable to send a feature report.\n"); +// } +// +// memset(buf,0,sizeof(buf)); +// +// // Read a Feature Report from the device +// buf[0] = 0x2; +// res = hid_get_feature_report(handle, buf, sizeof(buf)); +// if (res < 0) { +// printf("Unable to get a feature report.\n"); +// printf("%ls", hid_error(handle)); +// } +// else { +// // Print out the returned buffer. +// printf("Feature Report\n "); +// for (i = 0; i < res; i++) +// printf("%02hhx ", buf[i]); +// printf("\n"); +// } +// +// memset(buf,0,sizeof(buf)); +// +// // Toggle LED (cmd 0x80). The first byte is the report number (0x1). +// buf[0] = 0x1; +// buf[1] = 0x80; +// res = hid_write(handle, buf, 17); +// if (res < 0) { +// printf("Unable to write()\n"); +// printf("Error: %ls\n", hid_error(handle)); +// } +// +// +// // Request state (cmd 0x81). The first byte is the report number (0x1). +// buf[0] = 0x1; +// buf[1] = 0x81; +// hid_write(handle, buf, 17); +// if (res < 0) +// printf("Unable to write() (2)\n"); - memset(buf,0,sizeof(buf)); - // Toggle LED (cmd 0x80). The first byte is the report number (0x1). - buf[0] = 0x1; - buf[1] = 0x80; - res = hid_write(handle, buf, 17); - if (res < 0) { - printf("Unable to write()\n"); - printf("Error: %ls\n", hid_error(handle)); + for ( int i=0; i<8; i++ ){ + printf("bitmask test, %i, %i, %02hhx\n", i, BITMASK1(i), BITMASK1(i) ); } - - - // Request state (cmd 0x81). The first byte is the report number (0x1). - buf[0] = 0x1; - buf[1] = 0x81; - hid_write(handle, buf, 17); - if (res < 0) - printf("Unable to write() (2)\n"); // Read requested state. hid_read() has been set to be // non-blocking by the call to hid_set_nonblocking() above. // This loop demonstrates the non-blocking nature of hid_read(). res = 0; - while (res == 0) { + while (true) { res = hid_read(handle, buf, sizeof(buf)); - if (res == 0) - printf("waiting...\n"); - if (res < 0) - printf("Unable to read()\n"); +// if (res == 0) +// printf("waiting...\n"); +// if (res < 0) +// printf("Unable to read()\n"); + if ( res > 0 ) { +// printf("Data read:\n"); + // Print out the returned buffer. + hid_device_element * cur_element = descriptor->first; + for ( int i = 0; i < res; i++){ + char curbyte = buf[i]; + printf("byte %02hhx \t", buf[i]); + // read byte: + if ( cur_element->resolution < 8 ){ + int bitindex = 0; + while ( bitindex < 8 ){ + // read bit + cur_element->value = (curbyte >> bitindex) & BITMASK1( cur_element->resolution ); + printf("element page %i, usage %i, type %i, index %i, value %i\n", cur_element->usage_page, cur_element->usage, cur_element->type, cur_element->index, cur_element->value ); + bitindex += cur_element->resolution; + cur_element = cur_element->next; + } + } else if ( cur_element->resolution == 8 ){ + cur_element->value = curbyte; + printf("element page %i, usage %i, type %i, index %i, value %i\n", cur_element->usage_page, cur_element->usage, cur_element->type, cur_element->index,cur_element->value ); + cur_element = cur_element->next; + } // else: larger than 8 bits + } + printf("\n"); + } #ifdef WIN32 Sleep(500); #else - usleep(500*1000); + usleep(500*100); #endif } - printf("Data read:\n "); - // Print out the returned buffer. - for (i = 0; i < res; i++) - printf("%02hhx ", buf[i]); - printf("\n"); hid_close(handle); From b0b63016a1d47b0b521a9fe4d8cee1040a56eb50 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Tue, 10 Sep 2013 13:03:20 +0200 Subject: [PATCH 06/27] add hidapi_parser example --- Makefile.am | 2 + hidapi_parser/hidapi_parser.c | 415 ++++++++++++++++++++++++++++++++++ hidapi_parser/hidapi_parser.h | 50 ++++ hidapi_parser/main.c | 117 ++++++++++ 4 files changed, 584 insertions(+) create mode 100644 hidapi_parser/hidapi_parser.c create mode 100644 hidapi_parser/hidapi_parser.h create mode 100644 hidapi_parser/main.c diff --git a/Makefile.am b/Makefile.am index cf4f7ca4..ac9bd2bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,8 +31,10 @@ if OS_WINDOWS SUBDIRS += windows endif +SUBDIRS += hidapi_parser SUBDIRS += hidtest + if BUILD_TESTGUI SUBDIRS += testgui endif diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c new file mode 100644 index 00000000..f12ecf7d --- /dev/null +++ b/hidapi_parser/hidapi_parser.c @@ -0,0 +1,415 @@ +#include +#include + +#include "hidapi_parser.h" + +#define DEBUG_PARSER + +//// ---------- HID descriptor parser + +// main items +#define HID_INPUT 0x80 +#define HID_OUTPUT 0x90 +#define HID_COLLECTION 0xA0 +#define HID_FEATURE 0xB0 +#define HID_END_COLLECTION 0xC0 + +// HID Report Items from HID 1.11 Section 6.2.2 +#define HID_USAGE_PAGE 0x04 +#define HID_USAGE 0x08 +#define HID_USAGE_MIN 0x18 +#define HID_USAGE_MAX 0x28 + +#define HID_DESIGNATOR_INDEX 0x38 +#define HID_DESIGNATOR_MIN 0x48 +#define HID_DESIGNATOR_MAX 0x58 + +#define HID_STRING_INDEX 0x78 +#define HID_STRING_MIN 0x88 +#define HID_STRING_MAX 0x98 + +#define HID_DELIMITER 0xA8 + +#define HID_LOGICAL_MIN 0x14 +#define HID_LOGICAL_MAX 0x24 + +#define HID_PHYSICAL_MIN 0x34 +#define HID_PHYSICAL_MAX 0x44 + +#define HID_UNIT_EXPONENT 0x54 +#define HID_UNIT 0x64 + +#define HID_REPORT_SIZE 0x74 +#define HID_REPORT_ID 0x84 + +#define HID_REPORT_COUNT 0x94 + +#define HID_PUSH 0xA4 +#define HID_POP 0xB4 + +#define HID_RESERVED 0xC4 // above this it is all reserved + + +// HID Report Usage Pages from HID Usage Tables 1.12 Section 3, Table 1 +// #define HID_USAGE_PAGE_GENERICDESKTOP 0x01 +// #define HID_USAGE_PAGE_KEY_CODES 0x07 +// #define HID_USAGE_PAGE_LEDS 0x08 +// #define HID_USAGE_PAGE_BUTTONS 0x09 + +// HID Report Usages from HID Usage Tables 1.12 Section 4, Table 6 +// #define HID_USAGE_POINTER 0x01 +// #define HID_USAGE_MOUSE 0x02 +// #define HID_USAGE_JOYSTICK 0x04 +// #define HID_USAGE_KEYBOARD 0x06 +// #define HID_USAGE_X 0x30 +// #define HID_USAGE_Y 0x31 +// #define HID_USAGE_Z 0x32 +// #define HID_USAGE_RX 0x33 +// #define HID_USAGE_RY 0x34 +// #define HID_USAGE_RZ 0x35 +// #define HID_USAGE_SLIDER 0x36 +// #define HID_USAGE_DIAL 0x37 +// #define HID_USAGE_WHEEL 0x38 + + +// HID Report Collection Types from HID 1.12 6.2.2.6 +#define HID_COLLECTION_PHYSICAL 0x00 +#define HID_COLLECTION_APPLICATION 0x01 +#define HID_COLLECTION_LOGICAL 0x02 +#define HID_COLLECTION_REPORT 0x03 +#define HID_COLLECTION_NAMED_ARRAY 0x04 +#define HID_COLLECTION_USAGE_SWITCH 0x05 +#define HID_COLLECTION_USAGE_MODIFIER 0x06 +#define HID_COLLECTION_RESERVED 0x07 +#define HID_COLLECTION_VENDOR 0x80 + +// HID Input/Output/Feature Item Data (attributes) from HID 1.11 6.2.2.5 +/// more like flags - for input, output, and feature +#define HID_ITEM_CONSTANT 0x1 // data(0), constant(1) +#define HID_ITEM_VARIABLE 0x2 // array(0), variable(1) +#define HID_ITEM_RELATIVE 0x4 // absolute(0), relative(1) +#define HID_ITEM_WRAP 0x8 // no wrap(0), wrap(1) +#define HID_ITEM_LINEAR 0x10 // linear(0), non linear(1) +#define HID_ITEM_PREFERRED 0x20 // no preferred(0), preferred(1) +#define HID_ITEM_NULL 0x40 // no null(0), null(1) +#define HID_ITEM_VOLATILE 0x60 // non volatile(0), volatile(1) +#define HID_ITEM_BITFIELD 0x80 // bit field(0), buffered bytes(1) + +// Report Types from HID 1.11 Section 7.2.1 +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + + +#define BITMASK1(n) ((1ULL << (n)) - 1ULL) + +int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ){ + struct hid_device_element * prev_element; + int current_usage_page; + int current_usage; + int current_usages[256]; + int current_usage_index = 0; + int current_usage_min = -1; + int current_usage_max = -1; + int current_logical_min; + int current_logical_max; + int current_physical_min; + int current_physical_max; + int current_report_count; + int current_report_id; + int current_report_size; + char current_input; + char current_output; + int collection_nesting = 0; + + int next_byte_tag = -1; + int next_byte_size = 0; + int next_byte_type = 0; + int next_val = 0; + + int toadd = 0; + int byte_count = 0; + + int i,j; + + descriptor->num_elements = 0; + for ( i = 0; i < size; i++){ +#ifdef DEBUG_PARSER + printf("\n%02hhx ", descr_buf[i]); + printf("\tbyte_type %i, %i, %i \t", next_byte_tag, next_byte_size, next_val); +#endif + if ( next_byte_tag != -1 ){ + toadd = descr_buf[i]; + for ( j=0; jindex = descriptor->num_elements; + new_element->io_type = 1; + new_element->type = next_val; //TODO: parse this for more detailed info + + new_element->usage_page = current_usage_page; + if ( current_usage_min != -1 ){ + new_element->usage = current_usage_min + j; + } else { + new_element->usage = current_usages[j]; + } + new_element->logical_min = current_logical_min; + new_element->logical_max = current_logical_max; + new_element->phys_min = current_physical_min; + new_element->phys_max = current_physical_max; + + new_element->report_size = current_report_size; + new_element->report_id = current_report_id; + new_element->report_index = j; + + new_element->value = 0; + if ( descriptor->num_elements == 0 ){ + descriptor->first = new_element; + } else { + prev_element->next = new_element; + } + descriptor->num_elements++; + prev_element = new_element; + } + current_usage_min = -1; + current_usage_max = -1; + current_usage_index = 0; + break; + case HID_OUTPUT: +#ifdef DEBUG_PARSER + printf("output: %i", next_val); +#endif + // add the elements for this report + for ( j=0; jindex = descriptor->num_elements; + new_element->io_type = 2; + new_element->type = next_val; //TODO: parse this for more detailed info + + new_element->usage_page = current_usage_page; + if ( current_usage_min != -1 ){ + new_element->usage = current_usage_min + j; + } else { + new_element->usage = current_usages[j]; + } + new_element->logical_min = current_logical_min; + new_element->logical_max = current_logical_max; + new_element->phys_min = current_physical_min; + new_element->phys_max = current_physical_max; + + new_element->report_size = current_report_size; + new_element->report_id = current_report_id; + new_element->report_index = j; + + new_element->value = 0; + if ( descriptor->num_elements == 0 ){ + descriptor->first = new_element; + } else { + prev_element->next = new_element; + } + descriptor->num_elements++; + prev_element = new_element; + } + current_usage_min = -1; + current_usage_max = -1; + current_usage_index = 0; + break; + case HID_FEATURE: +#ifdef DEBUG_PARSER + printf("feature: %i", next_val); +#endif + // add the elements for this report + for ( j=0; jindex = descriptor->num_elements; + new_element->io_type = 3; + new_element->type = next_val; //TODO: parse this for more detailed info + + new_element->usage_page = current_usage_page; + if ( current_usage_min != -1 ){ + new_element->usage = current_usage_min + j; + } else { + new_element->usage = current_usages[j]; + } + new_element->logical_min = current_logical_min; + new_element->logical_max = current_logical_max; + new_element->phys_min = current_physical_min; + new_element->phys_max = current_physical_max; + + new_element->report_size = current_report_size; + new_element->report_id = current_report_id; + new_element->report_index = j; + + new_element->value = 0; + if ( descriptor->num_elements == 0 ){ + descriptor->first = new_element; + } else { + prev_element->next = new_element; + } + descriptor->num_elements++; + prev_element = new_element; + } + current_usage_min = -1; + current_usage_max = -1; + current_usage_index = 0; + break; +#ifdef DEBUG_PARSER + default: + if ( next_byte_tag >= HID_RESERVED ){ + printf("reserved bytes 0x%02hhx, %i", next_byte_tag, next_val ); + } else { + printf("undefined byte type 0x%02hhx, %i", next_byte_tag, next_val ); + } +#endif + } + next_byte_tag = -1; + } + } else { +#ifdef DEBUG_PARSER + printf("\tsetting next byte type: %i, 0x%02hhx ", descr_buf[i], descr_buf[i] ); +#endif + if ( descr_buf[i] == HID_END_COLLECTION ){ // JUST one byte + collection_nesting--; +#ifdef DEBUG_PARSER + printf("\tend collection: %i, %i\n", collection_nesting, descr_buf[i] ); +#endif + } else { + byte_count = 0; + next_val = 0; + next_byte_tag = descr_buf[i] & 0xFC; + next_byte_type = descr_buf[i] & 0x0C; + next_byte_size = descr_buf[i] & 0x03; + if ( next_byte_size == 3 ){ + next_byte_size = 4; + } +#ifdef DEBUG_PARSER + printf("\t next byte type: 0x%02hhx, %i, %i ", next_byte_tag, next_byte_type, next_byte_size ); +#endif + } + } + } + return 0; +} + +float hid_element_map_logical( struct hid_device_element * element ){ + return 0.; +} + +float hid_element_map_physical( struct hid_device_element * element ){ + return 0.; +} + +int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * descriptor ){ + + return 0; +} diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h new file mode 100644 index 00000000..969ee199 --- /dev/null +++ b/hidapi_parser/hidapi_parser.h @@ -0,0 +1,50 @@ +#ifndef HIDAPI_PARSER_H__ +#define HIDAPI_PARSER_H__ + + +#define HIDAPI_MAX_DESCRIPTOR_SIZE 4096 + + +struct hid_device_descriptor { + int num_elements; +// int usage_page; +// int usage; + /** Pointer to the first element */ + struct hid_device_element *first; +}; + +struct hid_device_element { + int index; + + int io_type; // input(1), output(2), feature(3) + int type; // flags from the input/output report +// int vartype; // abs/relative + int usage_page; // usage page + int usage; // some kind of index (as from descriptor) + + int logical_min; + int logical_max; + + int phys_min; + int phys_max; + + int report_size; + int report_id; + int report_index; // index into the report + + int value; + + /** Pointer to the next element */ + struct hid_device_element *next; +}; + +int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ); + +int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * descriptor ); + +float hid_element_map_logical( struct hid_device_element * element ); +float hid_element_map_physical( struct hid_device_element * element ); + +// int hid_parse_feature_report( char* buf, int size, hid_device_descriptor * descriptor ); + +#endif diff --git a/hidapi_parser/main.c b/hidapi_parser/main.c new file mode 100644 index 00000000..b2024185 --- /dev/null +++ b/hidapi_parser/main.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +#include +#include "hidapi_parser.h" + + +// Headers needed for sleeping. +#ifdef _WIN32 + #include +#else + #include +#endif + +void list_devices( void ){ + struct hid_device_info *devs, *cur_dev; + devs = hid_enumerate(0x0, 0x0); + cur_dev = devs; + while (cur_dev) { + printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); + printf("\n"); + printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); + printf(" Product: %ls\n", cur_dev->product_string); + printf(" Release: %hx\n", cur_dev->release_number); + printf(" Interface: %d\n", cur_dev->interface_number); + printf("\n"); + cur_dev = cur_dev->next; + } + hid_free_enumeration(devs); +} + +// static hid_device * open_device( char vendor_id, char product_id ){ +// handle = +// return handle; +// } + +#define MAX_STR 255 + +void print_device_info( hid_device *handle ){ + wchar_t wstr[MAX_STR]; + int res; + // Read the Manufacturer String + wstr[0] = 0x0000; + res = hid_get_manufacturer_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read manufacturer string\n"); + printf("Manufacturer String: %ls\n", wstr); + + // Read the Product String + wstr[0] = 0x0000; + res = hid_get_product_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read product string\n"); + printf("Product String: %ls\n", wstr); + + // Read the Serial Number String + wstr[0] = 0x0000; + res = hid_get_serial_number_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read serial number string\n"); + printf("Serial Number String: (%d) %ls", wstr[0], wstr); + printf("\n"); + + // Read Indexed String 1 + wstr[0] = 0x0000; + res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); + if (res < 0) + printf("Unable to read indexed string 1\n"); + printf("Indexed String 1: %ls\n", wstr); +} + +int main(int argc, char* argv[]){ + int res; + unsigned char buf[256]; + unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; + + struct hid_device_descriptor *descriptor; + hid_device *handle; + +#ifdef WIN32 + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); +#endif + + if (hid_init()) + return -1; + list_devices(); + + handle = hid_open( 0x044f, 0xd003, NULL); + if (!handle) { + printf("unable to open device\n"); + return 1; + } + print_device_info( handle ); + + res = hid_get_report_descriptor( handle, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); + if (res < 0){ + printf("Unable to read report descriptor\n"); + return 1; + } else { + descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); + hid_parse_report_descriptor( descr_buf, res, descriptor ); + } + // Set the hid_read() function to be non-blocking. + hid_set_nonblocking(handle, 1); + +// Request state (cmd 0x81). The first byte is the report number (0x1). +// buf[0] = 0x1; +// buf[1] = 0x81; +// hid_write(handle, buf, 17); +// if (res < 0) +// printf("Unable to write() (2)\n"); + + +} \ No newline at end of file From 3710ad71a3834b4c4f5245f3d7872c36a180e9ee Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Tue, 10 Sep 2013 13:04:00 +0200 Subject: [PATCH 07/27] and the makefile --- hidapi_parser/Makefile.am | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 hidapi_parser/Makefile.am diff --git a/hidapi_parser/Makefile.am b/hidapi_parser/Makefile.am new file mode 100644 index 00000000..fd105d45 --- /dev/null +++ b/hidapi_parser/Makefile.am @@ -0,0 +1,21 @@ +AM_CFLAGS = -I$(top_srcdir)/hidapi/ -std=c99 +AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ -std=c99 + +## Linux +if OS_LINUX +noinst_PROGRAMS = hidapi_parser-libusb hidapi_parser-hidraw + +hidapi_parser_hidraw_SOURCES = hidapi_parser.c main.c +hidapi_parser_hidrawLDADD = $(top_builddir)/linux/libhidapi-hidraw.la + +hidapi_parser_libusb_SOURCES = hidapi_parser.c main.c +hidapi_parser_libusb_LDADD = $(top_builddir)/libusb/libhidapi-libusb.la +else + +noinst_PROGRAMS = hidapi_parser + +hidapi_parser_SOURCES = hidapi_parser.c main.c +# hidapi_parser_HEADERS = hidapi_parser.h +hidapi_parser_LDADD = $(top_builddir)/$(backend)/libhidapi.la + +endif From ea8d947ab4c1205515faa236cb551121d9ae8749 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Tue, 10 Sep 2013 13:04:19 +0200 Subject: [PATCH 08/27] and the configuration file --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index f926f8e0..5b7a4e0a 100644 --- a/configure.ac +++ b/configure.ac @@ -219,6 +219,7 @@ AC_SUBST(LTLDFLAGS) AC_CONFIG_FILES([Makefile \ hidtest/Makefile \ + hidapi_parser/Makefile \ libusb/Makefile \ linux/Makefile \ mac/Makefile \ From cdeb044cdfe61b5fea73da5f6a33569cfff8e208 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Tue, 10 Sep 2013 15:21:46 +0200 Subject: [PATCH 09/27] now also parsing the data --- hidapi_parser/Makefile.am | 7 +-- hidapi_parser/hidapi_parser.c | 109 +++++++++++++++++++++++++++------- hidapi_parser/hidapi_parser.h | 21 ++++--- hidapi_parser/main.c | 30 +++++++++- hidtest/hidtest.cpp | 6 +- 5 files changed, 136 insertions(+), 37 deletions(-) diff --git a/hidapi_parser/Makefile.am b/hidapi_parser/Makefile.am index fd105d45..c4c130d7 100644 --- a/hidapi_parser/Makefile.am +++ b/hidapi_parser/Makefile.am @@ -1,12 +1,11 @@ -AM_CFLAGS = -I$(top_srcdir)/hidapi/ -std=c99 -AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ -std=c99 - +AM_CFLAGS = -I$(top_srcdir)/hidapi/ +AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ ## Linux if OS_LINUX noinst_PROGRAMS = hidapi_parser-libusb hidapi_parser-hidraw hidapi_parser_hidraw_SOURCES = hidapi_parser.c main.c -hidapi_parser_hidrawLDADD = $(top_builddir)/linux/libhidapi-hidraw.la +hidapi_parser_hidraw_LDADD = $(top_builddir)/linux/libhidapi-hidraw.la hidapi_parser_libusb_SOURCES = hidapi_parser.c main.c hidapi_parser_libusb_LDADD = $(top_builddir)/libusb/libhidapi-libusb.la diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index f12ecf7d..4f9b1950 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -1,5 +1,6 @@ #include #include +// #include #include "hidapi_parser.h" @@ -111,13 +112,15 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de int current_usage_index = 0; int current_usage_min = -1; int current_usage_max = -1; - int current_logical_min; - int current_logical_max; - int current_physical_min; - int current_physical_max; + int current_logical_min = 0; + int current_logical_max = 0; + int current_physical_min = 0; + int current_physical_max = 0; int current_report_count; int current_report_id; int current_report_size; + int current_unit = 0; + int current_unit_exponent = 0; char current_input; char current_output; int collection_nesting = 0; @@ -127,7 +130,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de int next_byte_type = 0; int next_val = 0; - int toadd = 0; + unsigned char toadd = 0; int byte_count = 0; int i,j; @@ -139,11 +142,12 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de printf("\tbyte_type %i, %i, %i \t", next_byte_tag, next_byte_size, next_val); #endif if ( next_byte_tag != -1 ){ - toadd = descr_buf[i]; - for ( j=0; jlogical_min = current_logical_min; new_element->logical_max = current_logical_max; - new_element->phys_min = current_physical_min; - new_element->phys_max = current_physical_max; + if ( (current_physical_min == 0) && (current_physical_max == 0) ){ + new_element->phys_min = current_logical_min; + new_element->phys_max = current_logical_max; + + } else { + new_element->phys_min = current_physical_min; + new_element->phys_max = current_physical_max; + } + new_element->unit = current_unit; + new_element->unit_exponent = current_unit_exponent; new_element->report_size = current_report_size; new_element->report_id = current_report_id; @@ -284,6 +296,9 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de current_usage_min = -1; current_usage_max = -1; current_usage_index = 0; + current_physical_min = 0; + current_physical_max = 0; + current_unit_exponent = 0; break; case HID_OUTPUT: #ifdef DEBUG_PARSER @@ -304,8 +319,16 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de } new_element->logical_min = current_logical_min; new_element->logical_max = current_logical_max; - new_element->phys_min = current_physical_min; - new_element->phys_max = current_physical_max; + if ( (current_physical_min == 0) && (current_physical_max == 0) ){ + new_element->phys_min = current_logical_min; + new_element->phys_max = current_logical_max; + + } else { + new_element->phys_min = current_physical_min; + new_element->phys_max = current_physical_max; + } + new_element->unit = current_unit; + new_element->unit_exponent = current_unit_exponent; new_element->report_size = current_report_size; new_element->report_id = current_report_id; @@ -323,6 +346,9 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de current_usage_min = -1; current_usage_max = -1; current_usage_index = 0; + current_physical_min = 0; + current_physical_max = 0; + current_unit_exponent = 0; break; case HID_FEATURE: #ifdef DEBUG_PARSER @@ -343,8 +369,16 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de } new_element->logical_min = current_logical_min; new_element->logical_max = current_logical_max; - new_element->phys_min = current_physical_min; - new_element->phys_max = current_physical_max; + if ( (current_physical_min == 0) && (current_physical_max == 0) ){ + new_element->phys_min = current_logical_min; + new_element->phys_max = current_logical_max; + + } else { + new_element->phys_min = current_physical_min; + new_element->phys_max = current_physical_max; + } + new_element->unit = current_unit; + new_element->unit_exponent = current_unit_exponent; new_element->report_size = current_report_size; new_element->report_id = current_report_id; @@ -362,6 +396,9 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de current_usage_min = -1; current_usage_max = -1; current_usage_index = 0; + current_physical_min = 0; + current_physical_max = 0; + current_unit_exponent = 0; break; #ifdef DEBUG_PARSER default: @@ -402,14 +439,46 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de } float hid_element_map_logical( struct hid_device_element * element ){ - return 0.; + float result = element->logical_min + ( element->value/( element->logical_max - element->logical_min ) ); + return result; +} + +float hid_element_resolution( struct hid_device_element * element ){ + float result = 0; +// ( element->logical_max - element->logical_min) / ( ( element->phys_max - element->phys_min) * pow(10, element->unit_exponent) ); + return result; } float hid_element_map_physical( struct hid_device_element * element ){ - return 0.; + float result = 0; + return result; } int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * descriptor ){ + // Print out the returned buffer. + struct hid_device_element * cur_element = descriptor->first; + int i; + printf("-----------------------\n", buf[i]); + for ( i = 0; i < size; i++){ + unsigned char curbyte = buf[i]; + printf("byte %02hhx \t", buf[i]); + // read byte: + if ( cur_element->report_size < 8 ){ + int bitindex = 0; + while ( bitindex < 8 ){ + // read bit + cur_element->value = (curbyte >> bitindex) & BITMASK1( cur_element->report_size ); + printf("element page %i, usage %i, type %i, index %i, value %i\n", cur_element->usage_page, cur_element->usage, cur_element->type, cur_element->index, cur_element->value ); + bitindex += cur_element->report_size; + cur_element = cur_element->next; + } + } else if ( cur_element->report_size == 8 ){ + cur_element->value = curbyte; + printf("element page %i, usage %i, type %i, index %i, value %i\n", cur_element->usage_page, cur_element->usage, cur_element->type, cur_element->index,cur_element->value ); + cur_element = cur_element->next; + } // else: larger than 8 bits + } + printf("\n"); return 0; } diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 969ee199..508b706c 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -4,15 +4,6 @@ #define HIDAPI_MAX_DESCRIPTOR_SIZE 4096 - -struct hid_device_descriptor { - int num_elements; -// int usage_page; -// int usage; - /** Pointer to the first element */ - struct hid_device_element *first; -}; - struct hid_device_element { int index; @@ -28,6 +19,9 @@ struct hid_device_element { int phys_min; int phys_max; + int unit_exponent; + int unit; + int report_size; int report_id; int report_index; // index into the report @@ -38,10 +32,19 @@ struct hid_device_element { struct hid_device_element *next; }; +struct hid_device_descriptor { + int num_elements; +// int usage_page; +// int usage; + /** Pointer to the first element */ + struct hid_device_element *first; +}; + int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ); int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * descriptor ); +float hid_element_resolution( struct hid_device_element * element ); float hid_element_map_logical( struct hid_device_element * element ); float hid_element_map_physical( struct hid_device_element * element ); diff --git a/hidapi_parser/main.c b/hidapi_parser/main.c index b2024185..3ecfa042 100644 --- a/hidapi_parser/main.c +++ b/hidapi_parser/main.c @@ -103,6 +103,7 @@ int main(int argc, char* argv[]){ descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); hid_parse_report_descriptor( descr_buf, res, descriptor ); } + // Set the hid_read() function to be non-blocking. hid_set_nonblocking(handle, 1); @@ -113,5 +114,32 @@ int main(int argc, char* argv[]){ // if (res < 0) // printf("Unable to write() (2)\n"); - + // Read requested state. hid_read() has been set to be + // non-blocking by the call to hid_set_nonblocking() above. + // This loop demonstrates the non-blocking nature of hid_read(). + res = 0; + while (1) { + res = hid_read(handle, buf, sizeof(buf)); + if ( res > 0 ) { + hid_parse_input_report( buf, res, descriptor ); + } + #ifdef WIN32 + Sleep(500); + #else + usleep(500*100); + #endif + } + + + hid_close(handle); + + /* Free static HIDAPI objects. */ + hid_exit(); + +#ifdef WIN32 + system("pause"); +#endif + + return 0; + } \ No newline at end of file diff --git a/hidtest/hidtest.cpp b/hidtest/hidtest.cpp index 03b242a8..1839c0e8 100644 --- a/hidtest/hidtest.cpp +++ b/hidtest/hidtest.cpp @@ -590,9 +590,9 @@ int main(int argc, char* argv[]) // printf("Unable to write() (2)\n"); - for ( int i=0; i<8; i++ ){ - printf("bitmask test, %i, %i, %02hhx\n", i, BITMASK1(i), BITMASK1(i) ); - } +// for ( int i=0; i<8; i++ ){ +// printf("bitmask test, %i, %i, %02hhx\n", i, BITMASK1(i), BITMASK1(i) ); +// } // Read requested state. hid_read() has been set to be // non-blocking by the call to hid_set_nonblocking() above. From 295fe6f4e3f8eddb04a31af7193142665bc4d779 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 11:21:27 +0200 Subject: [PATCH 10/27] added the callback functions --- hidapi_parser/hidapi_parser.c | 40 +++++++++++++++++++++++++++++++++-- hidapi_parser/hidapi_parser.h | 36 +++++++++++++++++++++++++++++++ hidapi_parser/main.c | 23 +++++++++++++++++++- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index 4f9b1950..897161fe 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -4,7 +4,7 @@ #include "hidapi_parser.h" -#define DEBUG_PARSER +// #define DEBUG_PARSER //// ---------- HID descriptor parser @@ -104,6 +104,23 @@ #define BITMASK1(n) ((1ULL << (n)) - 1ULL) + +void hid_descriptor_init(struct hid_device_descriptor * devd){ + hid_set_descriptor_callback(devd, NULL, NULL); + hid_set_element_callback(devd, NULL, NULL); +} + +void hid_set_descriptor_callback( struct hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ){ + devd->_descriptor_callback = cb; + devd->_descriptor_data = user_data; +} + +void hid_set_element_callback( struct hid_device_descriptor * devd, hid_element_callback cb, void *user_data ){ + devd->_element_callback = cb; + devd->_element_data = user_data; +} + + int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ){ struct hid_device_element * prev_element; int current_usage_page; @@ -459,26 +476,45 @@ int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * struct hid_device_element * cur_element = descriptor->first; int i; - printf("-----------------------\n", buf[i]); +#ifdef DEBUG_PARSER + printf("-----------------------\n"); +#endif for ( i = 0; i < size; i++){ unsigned char curbyte = buf[i]; +#ifdef DEBUG_PARSER printf("byte %02hhx \t", buf[i]); +#endif // read byte: if ( cur_element->report_size < 8 ){ int bitindex = 0; while ( bitindex < 8 ){ // read bit cur_element->value = (curbyte >> bitindex) & BITMASK1( cur_element->report_size ); +#ifdef DEBUG_PARSER printf("element page %i, usage %i, type %i, index %i, value %i\n", cur_element->usage_page, cur_element->usage, cur_element->type, cur_element->index, cur_element->value ); +#endif bitindex += cur_element->report_size; + if ( descriptor->_element_callback != NULL ){ + descriptor->_element_callback( cur_element, descriptor->_element_data ); + } cur_element = cur_element->next; } } else if ( cur_element->report_size == 8 ){ cur_element->value = curbyte; +#ifdef DEBUG_PARSER printf("element page %i, usage %i, type %i, index %i, value %i\n", cur_element->usage_page, cur_element->usage, cur_element->type, cur_element->index,cur_element->value ); +#endif + if ( descriptor->_element_callback != NULL ){ + descriptor->_element_callback( cur_element, descriptor->_element_data ); + } cur_element = cur_element->next; } // else: larger than 8 bits } +#ifdef DEBUG_PARSER printf("\n"); +#endif + if ( descriptor->_descriptor_callback != NULL ){ + descriptor->_descriptor_callback( descriptor, descriptor->_descriptor_data ); + } return 0; } diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 508b706c..91a95762 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -3,6 +3,27 @@ #define HIDAPI_MAX_DESCRIPTOR_SIZE 4096 +#include + +struct hid_device_element; +struct hid_device_descriptor; + +// struct hid_element_cb; +// struct hid_descriptor_cb; + +typedef void (*hid_element_callback) ( struct hid_device_element *element, void *user_data); +typedef void (*hid_descriptor_callback) ( struct hid_device_descriptor *descriptor, void *user_data); + +// typedef struct _hid_element_cb { +// hid_element_callback cb; +// void *data; +// } hid_element_cb; +// +// typedef struct _hid_descriptor_cb { +// hid_descriptor_callback cb; +// void *data; +// } hid_descriptor_cb; + struct hid_device_element { int index; @@ -30,6 +51,7 @@ struct hid_device_element { /** Pointer to the next element */ struct hid_device_element *next; + }; struct hid_device_descriptor { @@ -38,8 +60,22 @@ struct hid_device_descriptor { // int usage; /** Pointer to the first element */ struct hid_device_element *first; + + /** pointers to callback function */ + hid_element_callback _element_callback; + void *_element_data; + hid_descriptor_callback _descriptor_callback; + void *_descriptor_data; }; +// typedef void (*event_cb_t)(const struct hid_device_element *element, void *user_data); + +void hid_descriptor_init(struct hid_device_descriptor * devd); + +void hid_set_descriptor_callback( struct hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ); +void hid_set_element_callback( struct hid_device_descriptor * devd, hid_element_callback cb, void *user_data ); + + int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ); int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * descriptor ); diff --git a/hidapi_parser/main.c b/hidapi_parser/main.c index 3ecfa042..bd4b66fd 100644 --- a/hidapi_parser/main.c +++ b/hidapi_parser/main.c @@ -71,7 +71,22 @@ void print_device_info( hid_device *handle ){ printf("Indexed String 1: %ls\n", wstr); } +static void my_element_cb(const struct hid_device_element *el, void *data) +{ + printf("in %s\t", __func__); + printf("element: usage %i, value %i, index %i\t", el->usage, el->value, el->index ); + printf("user_data: %s\n", (const char *)data); +} + +static void my_descriptor_cb(const struct hid_device_descriptor *dd, void *data) +{ + printf("in %s\t", __func__); +// printf("element: usage %i, value %i, index %i\n", el->usage, el->value, el->index ); + printf("user_data: %s\n", (const char *)data); +} + int main(int argc, char* argv[]){ + int res; unsigned char buf[256]; unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; @@ -95,13 +110,20 @@ int main(int argc, char* argv[]){ } print_device_info( handle ); + char my_custom_data[40] = "Hello!"; + res = hid_get_report_descriptor( handle, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); if (res < 0){ printf("Unable to read report descriptor\n"); return 1; } else { descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); + hid_descriptor_init( descriptor ); hid_parse_report_descriptor( descr_buf, res, descriptor ); + + + hid_set_descriptor_callback( descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); + hid_set_element_callback( descriptor, (hid_element_callback) my_element_cb, my_custom_data ); } // Set the hid_read() function to be non-blocking. @@ -130,7 +152,6 @@ int main(int argc, char* argv[]){ #endif } - hid_close(handle); /* Free static HIDAPI objects. */ From bcd6fc8750a594c86f94a6ef3ff6617c8427a7f2 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 11:44:44 +0200 Subject: [PATCH 11/27] use typedefs --- hidapi_parser/hidapi_parser.c | 26 ++++++++++++------------ hidapi_parser/hidapi_parser.h | 37 +++++++++++++++++------------------ hidapi_parser/main.c | 10 +++++----- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index 897161fe..758d750c 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -105,24 +105,24 @@ #define BITMASK1(n) ((1ULL << (n)) - 1ULL) -void hid_descriptor_init(struct hid_device_descriptor * devd){ +void hid_descriptor_init( hid_device_descriptor * devd){ hid_set_descriptor_callback(devd, NULL, NULL); hid_set_element_callback(devd, NULL, NULL); } -void hid_set_descriptor_callback( struct hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ){ +void hid_set_descriptor_callback( hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ){ devd->_descriptor_callback = cb; devd->_descriptor_data = user_data; } -void hid_set_element_callback( struct hid_device_descriptor * devd, hid_element_callback cb, void *user_data ){ +void hid_set_element_callback( hid_device_descriptor * devd, hid_element_callback cb, void *user_data ){ devd->_element_callback = cb; devd->_element_data = user_data; } -int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ){ - struct hid_device_element * prev_element; +int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descriptor * descriptor ){ + hid_device_element * prev_element; int current_usage_page; int current_usage; int current_usages[256]; @@ -273,7 +273,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 1; new_element->type = next_val; //TODO: parse this for more detailed info @@ -323,7 +323,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 2; new_element->type = next_val; //TODO: parse this for more detailed info @@ -373,7 +373,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 3; new_element->type = next_val; //TODO: parse this for more detailed info @@ -455,25 +455,25 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de return 0; } -float hid_element_map_logical( struct hid_device_element * element ){ +float hid_element_map_logical( hid_device_element * element ){ float result = element->logical_min + ( element->value/( element->logical_max - element->logical_min ) ); return result; } -float hid_element_resolution( struct hid_device_element * element ){ +float hid_element_resolution( hid_device_element * element ){ float result = 0; // ( element->logical_max - element->logical_min) / ( ( element->phys_max - element->phys_min) * pow(10, element->unit_exponent) ); return result; } -float hid_element_map_physical( struct hid_device_element * element ){ +float hid_element_map_physical( hid_device_element * element ){ float result = 0; return result; } -int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * descriptor ){ +int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descriptor ){ // Print out the returned buffer. - struct hid_device_element * cur_element = descriptor->first; + hid_device_element * cur_element = descriptor->first; int i; #ifdef DEBUG_PARSER diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 91a95762..187d44b8 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -5,14 +5,14 @@ #define HIDAPI_MAX_DESCRIPTOR_SIZE 4096 #include -struct hid_device_element; -struct hid_device_descriptor; +typedef struct _hid_device_element hid_device_element; +typedef struct _hid_device_descriptor hid_device_descriptor; // struct hid_element_cb; // struct hid_descriptor_cb; -typedef void (*hid_element_callback) ( struct hid_device_element *element, void *user_data); -typedef void (*hid_descriptor_callback) ( struct hid_device_descriptor *descriptor, void *user_data); +typedef void (*hid_element_callback) ( hid_device_element *element, void *user_data); +typedef void (*hid_descriptor_callback) ( hid_device_descriptor *descriptor, void *user_data); // typedef struct _hid_element_cb { // hid_element_callback cb; @@ -25,7 +25,7 @@ typedef void (*hid_descriptor_callback) ( struct hid_device_descriptor *descript // } hid_descriptor_cb; -struct hid_device_element { +typedef struct _hid_device_element { int index; int io_type; // input(1), output(2), feature(3) @@ -50,39 +50,38 @@ struct hid_device_element { int value; /** Pointer to the next element */ - struct hid_device_element *next; - -}; + hid_device_element *next; +} hid_device_element; -struct hid_device_descriptor { +typedef struct _hid_device_descriptor { int num_elements; // int usage_page; // int usage; /** Pointer to the first element */ - struct hid_device_element *first; + hid_device_element *first; /** pointers to callback function */ hid_element_callback _element_callback; void *_element_data; hid_descriptor_callback _descriptor_callback; void *_descriptor_data; -}; +} hid_device_descriptor; // typedef void (*event_cb_t)(const struct hid_device_element *element, void *user_data); -void hid_descriptor_init(struct hid_device_descriptor * devd); +void hid_descriptor_init( hid_device_descriptor * devd); -void hid_set_descriptor_callback( struct hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ); -void hid_set_element_callback( struct hid_device_descriptor * devd, hid_element_callback cb, void *user_data ); +void hid_set_descriptor_callback( hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ); +void hid_set_element_callback( hid_device_descriptor * devd, hid_element_callback cb, void *user_data ); -int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ); +int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descriptor * descriptor ); -int hid_parse_input_report( char* buf, int size, struct hid_device_descriptor * descriptor ); +int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descriptor ); -float hid_element_resolution( struct hid_device_element * element ); -float hid_element_map_logical( struct hid_device_element * element ); -float hid_element_map_physical( struct hid_device_element * element ); +float hid_element_resolution( hid_device_element * element ); +float hid_element_map_logical( hid_device_element * element ); +float hid_element_map_physical( hid_device_element * element ); // int hid_parse_feature_report( char* buf, int size, hid_device_descriptor * descriptor ); diff --git a/hidapi_parser/main.c b/hidapi_parser/main.c index bd4b66fd..a00f4f3e 100644 --- a/hidapi_parser/main.c +++ b/hidapi_parser/main.c @@ -1,7 +1,7 @@ #include +#include #include #include -#include #include #include "hidapi_parser.h" @@ -71,14 +71,14 @@ void print_device_info( hid_device *handle ){ printf("Indexed String 1: %ls\n", wstr); } -static void my_element_cb(const struct hid_device_element *el, void *data) +static void my_element_cb(const hid_device_element *el, void *data) { printf("in %s\t", __func__); printf("element: usage %i, value %i, index %i\t", el->usage, el->value, el->index ); printf("user_data: %s\n", (const char *)data); } -static void my_descriptor_cb(const struct hid_device_descriptor *dd, void *data) +static void my_descriptor_cb(const hid_device_descriptor *dd, void *data) { printf("in %s\t", __func__); // printf("element: usage %i, value %i, index %i\n", el->usage, el->value, el->index ); @@ -91,7 +91,7 @@ int main(int argc, char* argv[]){ unsigned char buf[256]; unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; - struct hid_device_descriptor *descriptor; + hid_device_descriptor *descriptor; hid_device *handle; #ifdef WIN32 @@ -117,7 +117,7 @@ int main(int argc, char* argv[]){ printf("Unable to read report descriptor\n"); return 1; } else { - descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); + descriptor = (hid_device_descriptor *) malloc( sizeof( hid_device_descriptor) ); hid_descriptor_init( descriptor ); hid_parse_report_descriptor( descr_buf, res, descriptor ); From fdc8d66e19405b1b66368fec530bc11c879f49ce Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 15:07:25 +0200 Subject: [PATCH 12/27] add some higher level functions, and start of improvement of the parser --- hidapi_parser/hidapi_parser.c | 173 +++++++++++++++++++++++++++++----- hidapi_parser/hidapi_parser.h | 21 ++++- 2 files changed, 167 insertions(+), 27 deletions(-) diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index 758d750c..66bb8715 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -110,6 +110,12 @@ void hid_descriptor_init( hid_device_descriptor * devd){ hid_set_element_callback(devd, NULL, NULL); } +void hid_free_descriptor( hid_device_descriptor * devd){ + free( devd ); +// hid_set_descriptor_callback(devd, NULL, NULL); +// hid_set_element_callback(devd, NULL, NULL); +} + void hid_set_descriptor_callback( hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ){ devd->_descriptor_callback = cb; devd->_descriptor_data = user_data; @@ -120,7 +126,6 @@ void hid_set_element_callback( hid_device_descriptor * devd, hid_element_callbac devd->_element_data = user_data; } - int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descriptor * descriptor ){ hid_device_element * prev_element; int current_usage_page; @@ -310,12 +315,12 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto descriptor->num_elements++; prev_element = new_element; } - current_usage_min = -1; - current_usage_max = -1; - current_usage_index = 0; - current_physical_min = 0; - current_physical_max = 0; - current_unit_exponent = 0; +// current_usage_min = -1; +// current_usage_max = -1; +// current_usage_index = 0; +// current_physical_min = 0; +// current_physical_max = 0; +// current_unit_exponent = 0; break; case HID_OUTPUT: #ifdef DEBUG_PARSER @@ -360,12 +365,12 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto descriptor->num_elements++; prev_element = new_element; } - current_usage_min = -1; - current_usage_max = -1; - current_usage_index = 0; - current_physical_min = 0; - current_physical_max = 0; - current_unit_exponent = 0; +// current_usage_min = -1; +// current_usage_max = -1; +// current_usage_index = 0; +// current_physical_min = 0; +// current_physical_max = 0; +// current_unit_exponent = 0; break; case HID_FEATURE: #ifdef DEBUG_PARSER @@ -410,12 +415,12 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto descriptor->num_elements++; prev_element = new_element; } - current_usage_min = -1; - current_usage_max = -1; - current_usage_index = 0; - current_physical_min = 0; - current_physical_max = 0; - current_unit_exponent = 0; +// current_usage_min = -1; +// current_usage_max = -1; +// current_usage_index = 0; +// current_physical_min = 0; +// current_physical_max = 0; +// current_unit_exponent = 0; break; #ifdef DEBUG_PARSER default: @@ -471,10 +476,42 @@ float hid_element_map_physical( hid_device_element * element ){ return result; } +hid_device_element * hid_get_next_input_element( hid_device_element * curel ){ + + hid_device_element * nextel = curel->next; + while ( nextel != NULL ){ + if ( nextel->io_type == 1 ){ + return nextel; + } else { + nextel = nextel->next; + } + } + return curel; // return the previous element + // is NULL +} + int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descriptor ){ + ///TODO: parse input from descriptors with report size like 12 correctly + // Print out the returned buffer. hid_device_element * cur_element = descriptor->first; int i; + int next_byte_size; + int next_mod_bit_size; + int byte_count = 0; + int next_val = 0; + +// cur_element = hid_get_next_input_element( cur_element ); +// if ( cur_element == NULL ){ return 0; } + if ( cur_element->io_type != 1 ){ + cur_element = hid_get_next_input_element(cur_element); + } + next_byte_size = cur_element->report_size/8; + next_mod_bit_size = cur_element->report_size%8; + +#ifdef DEBUG_PARSER + printf("report_size %i, bytesize %i, bitsize %i \t", cur_element->report_size, next_byte_size, next_mod_bit_size ); +#endif #ifdef DEBUG_PARSER printf("-----------------------\n"); @@ -484,7 +521,7 @@ int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descrip #ifdef DEBUG_PARSER printf("byte %02hhx \t", buf[i]); #endif - // read byte: + // read byte: if ( cur_element->report_size < 8 ){ int bitindex = 0; while ( bitindex < 8 ){ @@ -497,7 +534,14 @@ int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descrip if ( descriptor->_element_callback != NULL ){ descriptor->_element_callback( cur_element, descriptor->_element_data ); } - cur_element = cur_element->next; + cur_element = hid_get_next_input_element( cur_element ); +// if ( cur_element == NULL ){ return 0; } + next_byte_size = cur_element->report_size/8; + next_mod_bit_size = cur_element->report_size%8; + +#ifdef DEBUG_PARSER + printf("report_size %i, bytesize %i, bitsize %i \t", cur_element->report_size, next_byte_size, next_mod_bit_size ); +#endif } } else if ( cur_element->report_size == 8 ){ cur_element->value = curbyte; @@ -507,9 +551,44 @@ int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descrip if ( descriptor->_element_callback != NULL ){ descriptor->_element_callback( cur_element, descriptor->_element_data ); } - cur_element = cur_element->next; - } // else: larger than 8 bits + cur_element = hid_get_next_input_element( cur_element ); +// if ( cur_element == NULL ){ return 0; } + next_byte_size = cur_element->report_size/8; + next_mod_bit_size = cur_element->report_size%8; + +#ifdef DEBUG_PARSER + printf("report_size %i, bytesize %i, bitsize %i \t", cur_element->report_size, next_byte_size, next_mod_bit_size ); +#endif + } else if ( cur_element->report_size == 16 ){ + int shift = byte_count*8; + next_val |= (int)(((unsigned char)(curbyte)) << shift); +#ifdef DEBUG_PARSER + printf("\t nextval shift: %i", next_val); +#endif + byte_count++; + if ( byte_count == next_byte_size ){ + cur_element->value = next_val; + +#ifdef DEBUG_PARSER + printf("element page %i, usage %i, type %i, index %i, value %i\n", cur_element->usage_page, cur_element->usage, cur_element->type, cur_element->index,cur_element->value ); +#endif + if ( descriptor->_element_callback != NULL ){ + descriptor->_element_callback( cur_element, descriptor->_element_data ); + } + cur_element = hid_get_next_input_element( cur_element ); +// if ( cur_element == NULL ){ break; } + next_byte_size = cur_element->report_size/8; + next_mod_bit_size = cur_element->report_size%8; + +#ifdef DEBUG_PARSER + printf("report_size %i, bytesize %i, bitsize %i \t", cur_element->report_size, next_byte_size, next_mod_bit_size ); +#endif + byte_count = 0; + next_val = 0; + } + } } + #ifdef DEBUG_PARSER printf("\n"); #endif @@ -518,3 +597,51 @@ int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descrip } return 0; } + + + +hid_device_descriptor * hid_read_descriptor( hid_device * devd ){ + hid_device_descriptor * descriptor; + unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; + int res; + res = hid_get_report_descriptor( devd, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); + if (res < 0){ + printf("Unable to read report descriptor\n"); + return NULL; + } else { + descriptor = (hid_device_descriptor *) malloc( sizeof( hid_device_descriptor) ); + hid_descriptor_init( descriptor ); + hid_parse_report_descriptor( descr_buf, res, descriptor ); + return descriptor; + } +} + +hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number ){ + hid_device * handle = hid_open( vendor, product, serial_number ); + if (!handle){ + return NULL; + } + hid_device_descriptor * newdesc = hid_read_descriptor( handle ); + if ( newdesc == NULL ){ + hid_close( handle ); + return NULL; + } + hid_dev_desc * newdevdesc = (hid_dev_desc *) malloc( sizeof( hid_dev_desc ) ); + struct hid_device_info * newinfo = hid_enumerate(vendor,product); + newdevdesc->device = handle; + //TODO: if serial_number is given, the info descriptor should also point to that one! + newdevdesc->info = newinfo; + newdevdesc->descriptor = newdesc; + + // Set the hid_read() function to be non-blocking. + hid_set_nonblocking( handle, 1); + + return newdevdesc; +} + +void hid_close_device( hid_dev_desc * devdesc ){ + hid_close( devdesc->device ); + hid_free_enumeration( devdesc->info ); + hid_free_descriptor( devdesc->descriptor ); + //TODO: more memory freeing? +} diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 187d44b8..572bdb23 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -3,7 +3,8 @@ #define HIDAPI_MAX_DESCRIPTOR_SIZE 4096 -#include + +#include typedef struct _hid_device_element hid_device_element; typedef struct _hid_device_descriptor hid_device_descriptor; @@ -24,6 +25,12 @@ typedef void (*hid_descriptor_callback) ( hid_device_descriptor *descriptor, voi // void *data; // } hid_descriptor_cb; +typedef struct _hid_dev_desc { + int index; + hid_device *device; + hid_device_descriptor *descriptor; + struct hid_device_info *info; +} hid_dev_desc; typedef struct _hid_device_element { int index; @@ -55,8 +62,7 @@ typedef struct _hid_device_element { typedef struct _hid_device_descriptor { int num_elements; -// int usage_page; -// int usage; + /** Pointer to the first element */ hid_device_element *first; @@ -70,13 +76,15 @@ typedef struct _hid_device_descriptor { // typedef void (*event_cb_t)(const struct hid_device_element *element, void *user_data); void hid_descriptor_init( hid_device_descriptor * devd); +void hid_free_descriptor( hid_device_descriptor * devd); void hid_set_descriptor_callback( hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ); void hid_set_element_callback( hid_device_descriptor * devd, hid_element_callback cb, void *user_data ); - int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descriptor * descriptor ); +hid_device_element * hid_get_next_input_element( hid_device_element * curel ); + int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descriptor ); float hid_element_resolution( hid_device_element * element ); @@ -85,4 +93,9 @@ float hid_element_map_physical( hid_device_element * element ); // int hid_parse_feature_report( char* buf, int size, hid_device_descriptor * descriptor ); +// higher level functions: +hid_device_descriptor * hid_read_descriptor( hid_device * devd ); +hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number ); +void hid_close_device( hid_dev_desc * devdesc ); + #endif From 066e578b44d68ebb3b4a13fd6a77336093bb48d0 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 15:07:47 +0200 Subject: [PATCH 13/27] use higher level elements, and print element information --- hidapi_parser/main.c | 52 +++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/hidapi_parser/main.c b/hidapi_parser/main.c index a00f4f3e..811285e5 100644 --- a/hidapi_parser/main.c +++ b/hidapi_parser/main.c @@ -38,6 +38,20 @@ void list_devices( void ){ #define MAX_STR 255 +void print_element_info( hid_device_element *element ){ + + printf( "index: %i, usage_page: %i, usage: %i, iotype: %i, type: %i, \n \ + \tlogical_min: %i, logical_max: %i, \n \ + \tphys_min: %i, phys_max: %i, unit_exponent: %i, unit: %i, \n \ + \treport_size: %i, report_id: %i, report_index: %i \n", + element->index, element->usage_page, element->usage, element->io_type, element->type, + element->logical_min, element->logical_max, + element->phys_min, element->phys_max, + element->unit_exponent, element->unit, + element->report_size, element->report_id, element->report_index ); + +} + void print_device_info( hid_device *handle ){ wchar_t wstr[MAX_STR]; int res; @@ -105,30 +119,42 @@ int main(int argc, char* argv[]){ handle = hid_open( 0x044f, 0xd003, NULL); if (!handle) { - printf("unable to open device\n"); - return 1; + printf("unable to open device\n"); + return 1; } print_device_info( handle ); char my_custom_data[40] = "Hello!"; - res = hid_get_report_descriptor( handle, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); - if (res < 0){ - printf("Unable to read report descriptor\n"); + descriptor = hid_read_descriptor( handle ); + if ( descriptor == NULL ){ + printf("unable to read descriptor\n"); return 1; - } else { - descriptor = (hid_device_descriptor *) malloc( sizeof( hid_device_descriptor) ); - hid_descriptor_init( descriptor ); - hid_parse_report_descriptor( descr_buf, res, descriptor ); - - - hid_set_descriptor_callback( descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); - hid_set_element_callback( descriptor, (hid_element_callback) my_element_cb, my_custom_data ); } +// res = hid_get_report_descriptor( handle, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); +// if (res < 0){ +// printf("Unable to read report descriptor\n"); +// return 1; +// } else { +// descriptor = (hid_device_descriptor *) malloc( sizeof( hid_device_descriptor) ); +// hid_descriptor_init( descriptor ); +// hid_parse_report_descriptor( descr_buf, res, descriptor ); +// +// } + + hid_set_descriptor_callback( descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); + hid_set_element_callback( descriptor, (hid_element_callback) my_element_cb, my_custom_data ); // Set the hid_read() function to be non-blocking. hid_set_nonblocking(handle, 1); + hid_device_element * cur_element = descriptor->first; + + while (cur_element) { + print_element_info( cur_element ); + cur_element = cur_element->next; + } + // Request state (cmd 0x81). The first byte is the report number (0x1). // buf[0] = 0x1; // buf[1] = 0x81; From bfed98f5395bd1857b037692e2fbb303a37c1573 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 15:08:03 +0200 Subject: [PATCH 14/27] add hidapi2osc program --- hidapi2osc/hidapi2osc.cpp | 528 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100644 hidapi2osc/hidapi2osc.cpp diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp new file mode 100644 index 00000000..d0e2990b --- /dev/null +++ b/hidapi2osc/hidapi2osc.cpp @@ -0,0 +1,528 @@ + + +#include +// #include +#include +#include + +#include +#include +#include +#include + + +#include "../hidapi/hidapi.h" +#include "../hidapi_parser/hidapi_parser.h" + +#include + +// Headers needed for sleeping. +#ifdef _WIN32 + #include +#else + #include +#endif + + +#include + +typedef std::map hid_map_t; + +hid_map_t hiddevices; // declares a vector of integers +int number_of_hids = 0; + +int done = 0; + +lo_address t; +lo_server s; +lo_server_thread st; + +static void osc_element_cb(const hid_device_element *el, void *data) +{ + lo_message m1 = lo_message_new(); + lo_message_add_int32( m1, *((int*) data) ); + lo_message_add_int32( m1, el->index ); + lo_message_add_int32( m1, el->usage_page ); + lo_message_add_int32( m1, el->usage ); + lo_message_add_int32( m1, el->value ); + lo_message_add_float( m1, hid_element_map_logical( el ) ); + lo_send_message_from( t, s, "/hid/element/data", m1 ); + lo_message_free(m1); +} + +static void osc_descriptor_cb(const hid_device_descriptor *dd, void *data) +{ + lo_message m1 = lo_message_new(); + lo_message_add_int32( m1, *((int*) data) ); + lo_message_add_int32( m1, dd->num_elements ); + lo_send_message_from( t, s, "/hid/device/data", m1 ); + lo_message_free(m1); +} + +void close_all_devices(){ + hid_map_t::const_iterator it; + for(it=hiddevices.begin(); it!=hiddevices.end(); ++it){ + hid_close_device( it->second ); + } + hiddevices.clear(); +} + +void open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number=NULL ){ + + hid_dev_desc * newdevdesc = hid_open_device( vendor, product, serial_number ); + + if (!newdevdesc){ + fprintf(stderr, "Unable to open device %d, %d\n", vendor, product ); + if ( serial_number != NULL ){ + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/open/error", "iis", vendor, product, serial_number ); + } else { + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/open/error", "ii", vendor, product ); + } + return; + } else { + hiddevices[ number_of_hids ] = newdevdesc; + if ( serial_number != NULL ){ + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/open", "iiis", number_of_hids, product, vendor, serial_number ); + } else { + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/open", "iii", number_of_hids, product, vendor ); + } + + newdevdesc->index = number_of_hids; + + hid_set_descriptor_callback( newdevdesc->descriptor, (hid_descriptor_callback) osc_descriptor_cb, &newdevdesc->index ); + hid_set_element_callback( newdevdesc->descriptor, (hid_element_callback) osc_element_cb, &newdevdesc->index ); + + number_of_hids++; + } +} + +void close_device( int joy_idx ){ + hid_dev_desc * hidtoclose = hiddevices.find( joy_idx )->second; + if ( !hidtoclose ){ + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/close/error", "i", joy_idx ); + } else { + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/closed", "iii", joy_idx, hidtoclose->info->vendor_id, hidtoclose->info->product_id ); + hid_close_device( hidtoclose ); + hiddevices.erase( hiddevices.find( joy_idx ) ); + } +} + + +/// OSC bits + +void error(int num, const char *m, const char *path); +int info_handler(const char *path, const char *types, lo_arg **argv, + int argc, void *data, void *user_data); + +// int openjoystick_handler(const char *path, const char *types, lo_arg **argv, +// int argc, void *data, void *user_data); + +int hid_open_handler(const char *path, const char *types, lo_arg **argv, + int argc, void *data, void *user_data); +int hid_close_handler(const char *path, const char *types, lo_arg **argv, + int argc, void *data, void *user_data); +int hid_info_handler(const char *path, const char *types, lo_arg **argv, + int argc, void *data, void *user_data); + +int element_hid_info_handler(const char *path, const char *types, lo_arg **argv, + int argc, void *data, void *user_data); + +int generic_handler(const char *path, const char *types, lo_arg **argv, + int argc, void *data, void *user_data); +int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, + void *data, void *user_data); + +int init_osc( char * ip, char *outport, char * port ){ + /* create liblo addres */ + t = lo_address_new(ip, outport); // change later to use other host + + lo_server_thread st = lo_server_thread_new(port, error); + + lo_server_thread_add_method(st, "/hid/open", "i", hid_open_handler, NULL); + lo_server_thread_add_method(st, "/hid/elements/info", "i", hid_element_info_handler, NULL); + lo_server_thread_add_method(st, "/hid/info", "i", hid_info_handler, NULL); + lo_server_thread_add_method(st, "/hid/close", "i", hid_close_handler, NULL); + + lo_server_thread_add_method(st, "/hidapi2osc/info", "", info_handler, NULL); + lo_server_thread_add_method(st, "/hidapi2osc/quit", "", quit_handler, NULL); + lo_server_thread_add_method(st, NULL, NULL, generic_handler, NULL); + + lo_server_thread_start(st); + + lo_server s = lo_server_thread_get_server( st ); + + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hidapi2osc/started", "" ); +} + +lo_message get_hid_info_msg( struct hid_device_info * info ) +{ + lo_message m1 = lo_message_new(); + lo_message_add_int32( m1, info->vendor_id ); + lo_message_add_int32( m1, info->product_id ); + lo_message_add_string( m1, info->path ); + lo_message_add_string( m1, info->serial_number ); + lo_message_add_string( m1, info->manufacturer_string ); + lo_message_add_string( m1, info->product_string ); + lo_message_add_int32( m1, info->release_number ); + lo_message_add_int32( m1, info->interface_number ); + return m1; +} + +lo_message get_hid_element_info_msg( struct hid_device_descriptor * desc ) +{ + lo_message m1 = lo_message_new(); + lo_message_add_int32( m1, el->index ); + lo_message_add_int32( m1, el->usage_page ); + lo_message_add_int32( m1, el->usage ); + lo_message_add_int32( m1, el->io_type ); + lo_message_add_int32( m1, el->type ); + lo_message_add_int32( m1, el->logical_min ); + lo_message_add_int32( m1, el->logical_max ); + lo_message_add_int32( m1, el->phys_min ); + lo_message_add_int32( m1, el->phys_max ); + lo_message_add_int32( m1, el->unit_exponent ); + lo_message_add_int32( m1, el->unit ); + lo_message_add_int32( m1, el->report_size ); + lo_message_add_int32( m1, el->report_id ); + lo_message_add_int32( m1, el->report_index ); + return m1; +} + + +void error(int num, const char *msg, const char *path) +{ + printf("liblo server error %d in path %s: %s\n", num, path, msg); + fflush(stdout); +} + +/* catch any incoming messages and display them. returning 1 means that the + * message has not been fully handled and the server should try other methods */ +int generic_handler(const char *path, const char *types, lo_arg **argv, + int argc, void *data, void *user_data) +{ + int i; + + printf("path: <%s>\n", path); + for (i=0; inext; + } + + lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); + + lo_message m1 = lo_message_new(); + lo_message_add_int32( m1,count ); + lo_bundle_add_message( b, "/hid/number", m1 ); + + cur_dev = devs; + while (cur_dev) { + lo_message m2 = get_hid_info_msg( cur_dev ); + lo_bundle_add_message( b, "/hid/info", m2 ); + cur_dev = cur_dev->next; + } + + if ( lo_send_bundle_from( t, s, b ) == -1 ){ + printf("hidapi2osc/info: OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t)); + } + lo_bundle_free( b ); + hid_free_enumeration(devs); + + fflush(stdout); + return 0; +} + +int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, + void *data, void *user_data) +{ + done = 1; + printf("hidapi2osc: allright, that's it, I quit\n"); + fflush(stdout); + + return 0; +} + +void send_elements_hid_info(int joy_idx) +{ + hid_dev_desc * hid = hiddevices.find( joy_idx )->second; + if ( hid == NULL ){ + return; + } + lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); + + lo_message m1 = lo_message_new(); + lo_message_add_int32( m1, joy_idx ); + lo_message_add_int32( m1, hid->descriptor->num_elements ); + lo_bundle_add_message( b, "/hid/element/number", m1 ); + + hid_device_element * cur_element = descriptor->first; + + while (cur_element) { + lo_message m2 = get_hid_element_info_msg( cur_element ); + lo_bundle_add_message( b, "/hid/element/info", m2 ); + cur_element = cur_element->next; + } + + if ( lo_send_bundle_from( t, s, b ) == -1 ){ + printf("hidapi2osc/info: OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t)); + } + lo_bundle_free( b ); +} + +void send_hid_info(int joy_idx) +{ + hid_dev_desc * hid = hiddevices.find( joy_idx )->second; + lo_message m1 = get_hid_info_msg( hid->info ); + lo_send_message_from( t, s, "/hid/info", m1 ); + lo_message_free(m1); +} + +int hid_info_handler(const char *path, const char *types, lo_arg **argv, int argc, + void *data, void *user_data) +{ + printf("hidapi2osc: joystick info handler\n"); + + send_hid_info( argv[0]->i ); +} + +int hid_elements_info_handler(const char *path, const char *types, lo_arg **argv, int argc, + void *data, void *user_data) +{ + printf("hidapi2osc: joystick elements info handler\n"); + + send_elements_hid_info( argv[0]->i ); +} + +int hid_open_handler(const char *path, const char *types, lo_arg **argv, int argc, + void *data, void *user_data) +{ + printf("hidapi2osc: joystick open handler\n"); + open_device( argv[0]->i ); +} + +int hid_close_handler(const char *path, const char *types, lo_arg **argv, int argc, + void *data, void *user_data) +{ + printf("hidapi2osc: joystick close handler\n"); + close_device( argv[0]->i ); +} + + + +/// end OSC stuff + + +int str2int(const char* str, int* val) +{ + char* endptr; + errno = 0; /* To distinguish success/failure after call */ + + *val = strtol(str, &endptr, 10); + + /* Check for various possible errors */ + if ((errno == ERANGE && (*val == LONG_MAX || *val == LONG_MIN)) + || (errno != 0 && *val == 0)) { + return 0; + } + + if (endptr == str) { + return 0; + } + + return 1; +} + +void print_device_info( hid_device *handle ){ + wchar_t wstr[MAX_STR]; + int res; + // Read the Manufacturer String + wstr[0] = 0x0000; + res = hid_get_manufacturer_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read manufacturer string\n"); + printf("Manufacturer String: %ls\n", wstr); + + // Read the Product String + wstr[0] = 0x0000; + res = hid_get_product_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read product string\n"); + printf("Product String: %ls\n", wstr); + + // Read the Serial Number String + wstr[0] = 0x0000; + res = hid_get_serial_number_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read serial number string\n"); + printf("Serial Number String: (%d) %ls", wstr[0], wstr); + printf("\n"); + + // Read Indexed String 1 + wstr[0] = 0x0000; + res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); + if (res < 0) + printf("Unable to read indexed string 1\n"); + printf("Indexed String 1: %ls\n", wstr); +} + +void list_devices( void ){ + struct hid_device_info *devs, *cur_dev; + devs = hid_enumerate(0x0, 0x0); + cur_dev = devs; + while (cur_dev) { + printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); + printf("\n"); + printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); + printf(" Product: %ls\n", cur_dev->product_string); + printf(" Release: %hx\n", cur_dev->release_number); + printf(" Interface: %d\n", cur_dev->interface_number); + printf("\n"); + cur_dev = cur_dev->next; + } + hid_free_enumeration(devs); +} + +void print_help(const char* prg) +{ + printf("Usage: %s [OPTION]\n", prg); +// printf("List available joysticks or test a joystick.\n"); +// printf("This programm uses SDL for doing its test instead of using the raw\n" +// "/dev/input/jsX interface\n"); + printf("\n"); + printf("Options:\n"); + printf(" --help Print this help\n"); + printf(" --version Print version number and exit\n"); + printf(" --list Search for available joysticks and list their properties\n"); +// printf(" --event JOYNUM Display the events that are received from the joystick\n"); + printf(" --osc Send the events that are received from the joystick\n"); + printf("\n"); + printf("Examples:\n"); + printf(" %s --list\n", prg); +// printf(" %s --test 1\n", prg); + printf(" %s --osc\n", prg); +} + + + +int main(int argc, char** argv) +{ + if (argc == 1) + { + print_help(argv[0]); + exit(1); + } + + // FIXME: We don't need video, but without it SDL will fail to work in SDL_WaitEvent() +// if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) + if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_EVENT | SDL_INIT_JOYSTICK) < 0) + { + fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); + exit(1); + } + else + { + atexit(SDL_Quit); + + if (argc == 2 && (strcmp(argv[1], "--help") == 0 || + strcmp(argv[1], "-h") == 0)) + { + print_help(argv[0]); + } + if (argc == 2 && (strcmp(argv[1], "--version") == 0)) + { + printf("hidapi2osc 0.1.0\n"); + exit(EXIT_SUCCESS); + } + else if (argc == 2 && (strcmp(argv[1], "--list") == 0 || + (strcmp(argv[1], "-l") == 0))) + { + list_devices(); + } +// else if (argc == 3 && (strcmp(argv[1], "--event") == 0 || +// strcmp(argv[1], "-e") == 0)) +// { +// int joy_idx; +// if (!str2int(argv[2], &joy_idx)) +// { +// fprintf(stderr, "Error: JOYSTICKNUM argument must be a number, but was '%s'\n", argv[2]); +// exit(1); +// } +// +// } +// fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); +// } + else if (argc == 2 && (strcmp(argv[1], "--osc") == 0 || + strcmp(argv[1], "-o") == 0)) + { + + char *port = "57151"; + char *outport = "57120"; + char *ip = "127.0.0.1"; + + if ( argc == 5 ) + { + ip = argv[4]; + port = argv[3]; + outport = argv[2]; + } + else if ( argc == 4 ) + { + port = argv[3]; + outport = argv[2]; + } + else if ( argc == 3 ) + { + outport = argv[2]; + } + + init_osc( ip, outport, port ); + + printf("Entering hid read loop, press Ctrl-c to exit\n"); + + int res = 0; + + while(!done){ + res = hid_read(handle, buf, sizeof(buf)); + if ( res > 0 ) { + hid_parse_input_report( buf, res, descriptor ); + } + #ifdef WIN32 + Sleep(50); + #else + usleep(500*10); + #endif + } + close_all_hids(); + + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hidapi2osc/quit", "s", "nothing more to do, quitting" ); + lo_server_thread_free( st ); + lo_address_free( t ); + } + else + { + fprintf(stderr, "%s: unknown arguments\n", argv[0]); + fprintf(stderr, "Try '%s --help' for more informations\n", argv[0]); + } + } +} + +/* EOF */ From 7ab59a38da070ad9b5c4d9301f8146954474cd17 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 16:01:56 +0200 Subject: [PATCH 15/27] towards building the osc test program --- Makefile.am | 1 + configure.ac | 3 ++ hidapi2osc/Makefile.am | 20 ++++++++ hidapi2osc/hidapi2osc.cpp | 92 +++++++++++++++++++++++------------ hidapi_parser/hidapi_parser.c | 2 +- hidapi_parser/hidapi_parser.h | 15 +++--- 6 files changed, 93 insertions(+), 40 deletions(-) create mode 100644 hidapi2osc/Makefile.am diff --git a/Makefile.am b/Makefile.am index ac9bd2bf..803620a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,6 +32,7 @@ SUBDIRS += windows endif SUBDIRS += hidapi_parser +SUBDIRS += hidapi2osc SUBDIRS += hidtest diff --git a/configure.ac b/configure.ac index 5b7a4e0a..ebb986b4 100644 --- a/configure.ac +++ b/configure.ac @@ -217,9 +217,12 @@ fi AC_SUBST(LTLDFLAGS) +PKG_CHECK_MODULES( LIBLO, liblo) + AC_CONFIG_FILES([Makefile \ hidtest/Makefile \ hidapi_parser/Makefile \ + hidapi2osc/Makefile \ libusb/Makefile \ linux/Makefile \ mac/Makefile \ diff --git a/hidapi2osc/Makefile.am b/hidapi2osc/Makefile.am new file mode 100644 index 00000000..e4b09cab --- /dev/null +++ b/hidapi2osc/Makefile.am @@ -0,0 +1,20 @@ +AM_CFLAGS = $(LIBLO_CFLAGS) -I$(top_srcdir)/hidapi/ -I$(top_srcdir)/hidapi_parser/ +AM_CPPFLAGS = $(LIBLO_CFLAGS) -I$(top_srcdir)/hidapi/ -I$(top_srcdir)/hidapi_parser/ +## Linux +if OS_LINUX +noinst_PROGRAMS = hidapi2osc-libusb hidapi2osc-hidraw + +hidapi2osc_hidraw_SOURCES = $(top_srcdir)/hidapi_parser/hidapi_parser.c hidapi2osc.cpp +hidapi2osc_hidraw_LDADD = $(top_builddir)/linux/libhidapi-hidraw.la $(LIBLO_LIBS) + +hidapi2osc_libusb_SOURCES = $(top_srcdir)/hidapi_parser/hidapi_parser.c hidapi2osc.cpp +hidapi2osc_libusb_LDADD = $(top_builddir)/libusb/libhidapi-libusb.la $(LIBLO_LIBS) +else + +noinst_PROGRAMS = hidapi2osc + +hidapi2osc_SOURCES = $(top_srcdir)/hidapi_parser/hidapi_parser.c hidapi2osc.cpp +# hidapi_parser_HEADERS = hidapi_parser.h +hidapi2osc_LDADD = $(top_builddir)/$(backend)/libhidapi.la $(LIBLO_LIBS) + +endif diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index d0e2990b..5e670f72 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -10,11 +10,13 @@ #include #include +#include -#include "../hidapi/hidapi.h" -#include "../hidapi_parser/hidapi_parser.h" +// #include "../hidapi/hidapi.h" +// #include "../hidapi_parser/hidapi_parser.h" -#include +#include "hidapi.h" +#include "hidapi_parser.h" // Headers needed for sleeping. #ifdef _WIN32 @@ -26,18 +28,21 @@ #include -typedef std::map hid_map_t; +typedef std::map hid_map_t; hid_map_t hiddevices; // declares a vector of integers int number_of_hids = 0; int done = 0; +#define MAX_STR 255 + + lo_address t; lo_server s; lo_server_thread st; -static void osc_element_cb(const hid_device_element *el, void *data) +static void osc_element_cb( hid_device_element *el, void *data) { lo_message m1 = lo_message_new(); lo_message_add_int32( m1, *((int*) data) ); @@ -50,7 +55,7 @@ static void osc_element_cb(const hid_device_element *el, void *data) lo_message_free(m1); } -static void osc_descriptor_cb(const hid_device_descriptor *dd, void *data) +static void osc_descriptor_cb( hid_device_descriptor *dd, void *data) { lo_message m1 = lo_message_new(); lo_message_add_int32( m1, *((int*) data) ); @@ -124,7 +129,7 @@ int hid_close_handler(const char *path, const char *types, lo_arg **argv, int hid_info_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); -int element_hid_info_handler(const char *path, const char *types, lo_arg **argv, +int hid_element_info_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); int generic_handler(const char *path, const char *types, lo_arg **argv, @@ -138,8 +143,8 @@ int init_osc( char * ip, char *outport, char * port ){ lo_server_thread st = lo_server_thread_new(port, error); - lo_server_thread_add_method(st, "/hid/open", "i", hid_open_handler, NULL); - lo_server_thread_add_method(st, "/hid/elements/info", "i", hid_element_info_handler, NULL); + lo_server_thread_add_method(st, "/hid/open", "ii", hid_open_handler, NULL); +// lo_server_thread_add_method(st, "/hid/elements/info", "i", hid_element_info_handler, NULL); lo_server_thread_add_method(st, "/hid/info", "i", hid_info_handler, NULL); lo_server_thread_add_method(st, "/hid/close", "i", hid_close_handler, NULL); @@ -160,15 +165,35 @@ lo_message get_hid_info_msg( struct hid_device_info * info ) lo_message_add_int32( m1, info->vendor_id ); lo_message_add_int32( m1, info->product_id ); lo_message_add_string( m1, info->path ); - lo_message_add_string( m1, info->serial_number ); - lo_message_add_string( m1, info->manufacturer_string ); - lo_message_add_string( m1, info->product_string ); + + wchar_t* wstr = info->serial_number; + char* ascii = new char[wcslen(wstr) + 1]; + wcstombs( ascii, wstr, wcslen(wstr) ); + lo_message_add_string( m1, ascii ); + delete ascii; + + wstr = info->manufacturer_string; + ascii = new char[wcslen(wstr) + 1]; + wcstombs( ascii, wstr, wcslen(wstr) ); + lo_message_add_string( m1, ascii ); + delete ascii; + + wstr = info->product_string; + ascii = new char[wcslen(wstr) + 1]; + wcstombs( ascii, wstr, wcslen(wstr) ); + lo_message_add_string( m1, ascii ); + delete ascii; + +// lo_message_add_string( m1, info->serial_number ); +// lo_message_add_string( m1, info->manufacturer_string ); +// lo_message_add_string( m1, info->product_string ); + lo_message_add_int32( m1, info->release_number ); lo_message_add_int32( m1, info->interface_number ); return m1; } -lo_message get_hid_element_info_msg( struct hid_device_descriptor * desc ) +lo_message get_hid_element_info_msg( hid_device_element * el ) { lo_message m1 = lo_message_new(); lo_message_add_int32( m1, el->index ); @@ -222,7 +247,7 @@ int info_handler(const char *path, const char *types, lo_arg **argv, int argc, devs = hid_enumerate(0x0, 0x0); cur_dev = devs; - count = 0; + int count = 0; while (cur_dev) { count++; cur_dev = cur_dev->next; @@ -274,7 +299,7 @@ void send_elements_hid_info(int joy_idx) lo_message_add_int32( m1, hid->descriptor->num_elements ); lo_bundle_add_message( b, "/hid/element/number", m1 ); - hid_device_element * cur_element = descriptor->first; + hid_device_element * cur_element = hid->descriptor->first; while (cur_element) { lo_message m2 = get_hid_element_info_msg( cur_element ); @@ -316,7 +341,7 @@ int hid_open_handler(const char *path, const char *types, lo_arg **argv, int arg void *data, void *user_data) { printf("hidapi2osc: joystick open handler\n"); - open_device( argv[0]->i ); + open_device( argv[0]->i, argv[1]->i, NULL ); } int hid_close_handler(const char *path, const char *types, lo_arg **argv, int argc, @@ -433,14 +458,14 @@ int main(int argc, char** argv) // FIXME: We don't need video, but without it SDL will fail to work in SDL_WaitEvent() // if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) - if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_EVENT | SDL_INIT_JOYSTICK) < 0) - { - fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); - exit(1); - } - else - { - atexit(SDL_Quit); +// if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_EVENT | SDL_INIT_JOYSTICK) < 0) +// { +// fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); +// exit(1); +// } +// else +// { +// atexit(SDL_Quit); if (argc == 2 && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)) @@ -500,10 +525,14 @@ int main(int argc, char** argv) int res = 0; + hid_map_t::const_iterator it; + unsigned char buf[256]; while(!done){ - res = hid_read(handle, buf, sizeof(buf)); - if ( res > 0 ) { - hid_parse_input_report( buf, res, descriptor ); + for(it=hiddevices.begin(); it!=hiddevices.end(); ++it){ + res = hid_read( it->second->device, buf, sizeof(buf)); + if ( res > 0 ) { + hid_parse_input_report( buf, res, it->second->descriptor ); + } } #ifdef WIN32 Sleep(50); @@ -511,18 +540,17 @@ int main(int argc, char** argv) usleep(500*10); #endif } - close_all_hids(); + close_all_devices(); - lo_send_from( t, s, LO_TT_IMMEDIATE, "/hidapi2osc/quit", "s", "nothing more to do, quitting" ); - lo_server_thread_free( st ); - lo_address_free( t ); + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hidapi2osc/quit", "s", "nothing more to do, quitting" ); + lo_server_thread_free( st ); + lo_address_free( t ); } else { fprintf(stderr, "%s: unknown arguments\n", argv[0]); fprintf(stderr, "Try '%s --help' for more informations\n", argv[0]); } - } } /* EOF */ diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index 66bb8715..3684abd6 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -490,7 +490,7 @@ hid_device_element * hid_get_next_input_element( hid_device_element * curel ){ // is NULL } -int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descriptor ){ +int hid_parse_input_report( unsigned char* buf, int size, hid_device_descriptor * descriptor ){ ///TODO: parse input from descriptors with report size like 12 correctly // Print out the returned buffer. diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 572bdb23..7430109b 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -8,6 +8,7 @@ typedef struct _hid_device_element hid_device_element; typedef struct _hid_device_descriptor hid_device_descriptor; +typedef struct _hid_dev_desc hid_dev_desc; // struct hid_element_cb; // struct hid_descriptor_cb; @@ -25,14 +26,14 @@ typedef void (*hid_descriptor_callback) ( hid_device_descriptor *descriptor, voi // void *data; // } hid_descriptor_cb; -typedef struct _hid_dev_desc { +struct _hid_dev_desc { int index; hid_device *device; hid_device_descriptor *descriptor; struct hid_device_info *info; -} hid_dev_desc; +}; -typedef struct _hid_device_element { +struct _hid_device_element { int index; int io_type; // input(1), output(2), feature(3) @@ -58,9 +59,9 @@ typedef struct _hid_device_element { /** Pointer to the next element */ hid_device_element *next; -} hid_device_element; +}; -typedef struct _hid_device_descriptor { +struct _hid_device_descriptor { int num_elements; /** Pointer to the first element */ @@ -71,7 +72,7 @@ typedef struct _hid_device_descriptor { void *_element_data; hid_descriptor_callback _descriptor_callback; void *_descriptor_data; -} hid_device_descriptor; +}; // typedef void (*event_cb_t)(const struct hid_device_element *element, void *user_data); @@ -85,7 +86,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto hid_device_element * hid_get_next_input_element( hid_device_element * curel ); -int hid_parse_input_report( char* buf, int size, hid_device_descriptor * descriptor ); +int hid_parse_input_report( unsigned char* buf, int size, hid_device_descriptor * descriptor ); float hid_element_resolution( hid_device_element * element ); float hid_element_map_logical( hid_device_element * element ); From 9d4effbac8107695713713cb87b7bb5734f3f3c4 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 16:32:15 +0200 Subject: [PATCH 16/27] towards building --- hidapi2osc/hidapi2osc.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index 5e670f72..5f6e00b5 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -42,7 +42,7 @@ lo_address t; lo_server s; lo_server_thread st; -static void osc_element_cb( hid_device_element *el, void *data) +static void osc_element_cb( struct hid_device_element *el, void *data) { lo_message m1 = lo_message_new(); lo_message_add_int32( m1, *((int*) data) ); @@ -50,12 +50,12 @@ static void osc_element_cb( hid_device_element *el, void *data) lo_message_add_int32( m1, el->usage_page ); lo_message_add_int32( m1, el->usage ); lo_message_add_int32( m1, el->value ); - lo_message_add_float( m1, hid_element_map_logical( el ) ); +// lo_message_add_float( m1, hid_element_map_logical( el ) ); // TODO: this one is not found??? lo_send_message_from( t, s, "/hid/element/data", m1 ); lo_message_free(m1); } -static void osc_descriptor_cb( hid_device_descriptor *dd, void *data) +static void osc_descriptor_cb( struct hid_device_descriptor *dd, void *data) { lo_message m1 = lo_message_new(); lo_message_add_int32( m1, *((int*) data) ); @@ -67,14 +67,15 @@ static void osc_descriptor_cb( hid_device_descriptor *dd, void *data) void close_all_devices(){ hid_map_t::const_iterator it; for(it=hiddevices.begin(); it!=hiddevices.end(); ++it){ - hid_close_device( it->second ); + struct hid_dev_desc * devdesc = it->second; + hid_close_device( devdesc ); } hiddevices.clear(); } void open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number=NULL ){ - hid_dev_desc * newdevdesc = hid_open_device( vendor, product, serial_number ); + struct hid_dev_desc * newdevdesc = hid_open_device( vendor, product, serial_number ); if (!newdevdesc){ fprintf(stderr, "Unable to open device %d, %d\n", vendor, product ); @@ -102,7 +103,7 @@ void open_device( unsigned short vendor, unsigned short product, const wchar_t * } void close_device( int joy_idx ){ - hid_dev_desc * hidtoclose = hiddevices.find( joy_idx )->second; + struct hid_dev_desc * hidtoclose = hiddevices.find( joy_idx )->second; if ( !hidtoclose ){ lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/close/error", "i", joy_idx ); } else { From 601588c1aae443dda966a1cff1d5a94fc0b99622 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Wed, 11 Sep 2013 16:32:36 +0200 Subject: [PATCH 17/27] rename to c --- hidapi2osc/{hidapi2osc.cpp => hidapi2osc.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hidapi2osc/{hidapi2osc.cpp => hidapi2osc.c} (100%) diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.c similarity index 100% rename from hidapi2osc/hidapi2osc.cpp rename to hidapi2osc/hidapi2osc.c From 4f55c88ab0f6780f3fbadbf5151dd969d24107cc Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 00:51:44 +0200 Subject: [PATCH 18/27] rename back to cpp --- hidapi2osc/{hidapi2osc.c => hidapi2osc.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hidapi2osc/{hidapi2osc.c => hidapi2osc.cpp} (100%) diff --git a/hidapi2osc/hidapi2osc.c b/hidapi2osc/hidapi2osc.cpp similarity index 100% rename from hidapi2osc/hidapi2osc.c rename to hidapi2osc/hidapi2osc.cpp From b2875373d46931ebe53e018f7f2dd9338d738c5f Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 00:53:01 +0200 Subject: [PATCH 19/27] working hidapi2osc --- Makefile.am | 3 +- configure.ac | 2 +- hidapi2osc/hidapi2osc.cpp | 80 +++++--- hidapi2osc/supercollider/hidapi2osc-test.scd | 23 +++ hidapi_parser/hidapi_parser.c | 46 ++--- hidapi_parser/hidapi_parser.h | 66 +++--- hidapi_parser/main.c | 54 +++-- hidparsertest/hidparsertest.c | 202 +++++++++++++++++++ 8 files changed, 375 insertions(+), 101 deletions(-) create mode 100644 hidapi2osc/supercollider/hidapi2osc-test.scd create mode 100644 hidparsertest/hidparsertest.c diff --git a/Makefile.am b/Makefile.am index 803620a5..51c02f64 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,7 +31,8 @@ if OS_WINDOWS SUBDIRS += windows endif -SUBDIRS += hidapi_parser +# SUBDIRS += hidapi_parser +SUBDIRS += hidparsertest SUBDIRS += hidapi2osc SUBDIRS += hidtest diff --git a/configure.ac b/configure.ac index ebb986b4..7b193234 100644 --- a/configure.ac +++ b/configure.ac @@ -221,7 +221,7 @@ PKG_CHECK_MODULES( LIBLO, liblo) AC_CONFIG_FILES([Makefile \ hidtest/Makefile \ - hidapi_parser/Makefile \ + hidparsertest/Makefile \ hidapi2osc/Makefile \ libusb/Makefile \ linux/Makefile \ diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index 5f6e00b5..78ce0a78 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -15,8 +15,8 @@ // #include "../hidapi/hidapi.h" // #include "../hidapi_parser/hidapi_parser.h" -#include "hidapi.h" -#include "hidapi_parser.h" +#include +#include // Headers needed for sleeping. #ifdef _WIN32 @@ -103,13 +103,14 @@ void open_device( unsigned short vendor, unsigned short product, const wchar_t * } void close_device( int joy_idx ){ +// hid_map_t::const_iterator it = ; struct hid_dev_desc * hidtoclose = hiddevices.find( joy_idx )->second; - if ( !hidtoclose ){ + if ( hidtoclose == NULL ){ lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/close/error", "i", joy_idx ); } else { lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/closed", "iii", joy_idx, hidtoclose->info->vendor_id, hidtoclose->info->product_id ); hid_close_device( hidtoclose ); - hiddevices.erase( hiddevices.find( joy_idx ) ); + hiddevices.erase( joy_idx ); } } @@ -145,7 +146,7 @@ int init_osc( char * ip, char *outport, char * port ){ lo_server_thread st = lo_server_thread_new(port, error); lo_server_thread_add_method(st, "/hid/open", "ii", hid_open_handler, NULL); -// lo_server_thread_add_method(st, "/hid/elements/info", "i", hid_element_info_handler, NULL); + lo_server_thread_add_method(st, "/hid/elements/info", "i", hid_element_info_handler, NULL); lo_server_thread_add_method(st, "/hid/info", "i", hid_info_handler, NULL); lo_server_thread_add_method(st, "/hid/close", "i", hid_close_handler, NULL); @@ -167,23 +168,38 @@ lo_message get_hid_info_msg( struct hid_device_info * info ) lo_message_add_int32( m1, info->product_id ); lo_message_add_string( m1, info->path ); + //TODO: fix for proper conversion of unicode to ascii wchar_t* wstr = info->serial_number; - char* ascii = new char[wcslen(wstr) + 1]; - wcstombs( ascii, wstr, wcslen(wstr) ); - lo_message_add_string( m1, ascii ); - delete ascii; + char* ascii; + if ( wstr != NULL ){ + ascii = new char[wcslen(wstr) + 1]; + wcstombs( ascii, wstr, wcslen(wstr) ); + lo_message_add_string( m1, ascii ); + delete ascii; + } else { + lo_message_add_string( m1, "" ); + } wstr = info->manufacturer_string; - ascii = new char[wcslen(wstr) + 1]; - wcstombs( ascii, wstr, wcslen(wstr) ); - lo_message_add_string( m1, ascii ); - delete ascii; + if ( wstr != NULL ){ + ascii = new char[wcslen(wstr) + 1]; + wcstombs( ascii, wstr, wcslen(wstr) ); + lo_message_add_string( m1, ascii ); + delete ascii; + } else { + lo_message_add_string( m1, "" ); + } + wstr = info->product_string; - ascii = new char[wcslen(wstr) + 1]; - wcstombs( ascii, wstr, wcslen(wstr) ); - lo_message_add_string( m1, ascii ); - delete ascii; + if ( wstr != NULL ){ + ascii = new char[wcslen(wstr) + 1]; + wcstombs( ascii, wstr, wcslen(wstr) ); + lo_message_add_string( m1, ascii ); + delete ascii; + } else { + lo_message_add_string( m1, "" ); + } // lo_message_add_string( m1, info->serial_number ); // lo_message_add_string( m1, info->manufacturer_string ); @@ -242,8 +258,7 @@ int generic_handler(const char *path, const char *types, lo_arg **argv, int info_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) -{ - +{ struct hid_device_info *devs, *cur_dev; devs = hid_enumerate(0x0, 0x0); @@ -253,11 +268,11 @@ int info_handler(const char *path, const char *types, lo_arg **argv, int argc, count++; cur_dev = cur_dev->next; } - + lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); lo_message m1 = lo_message_new(); - lo_message_add_int32( m1,count ); + lo_message_add_int32( m1, count ); lo_bundle_add_message( b, "/hid/number", m1 ); cur_dev = devs; @@ -291,6 +306,7 @@ void send_elements_hid_info(int joy_idx) { hid_dev_desc * hid = hiddevices.find( joy_idx )->second; if ( hid == NULL ){ + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/elements/info/error", "i", joy_idx ); return; } lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); @@ -316,10 +332,14 @@ void send_elements_hid_info(int joy_idx) void send_hid_info(int joy_idx) { - hid_dev_desc * hid = hiddevices.find( joy_idx )->second; - lo_message m1 = get_hid_info_msg( hid->info ); - lo_send_message_from( t, s, "/hid/info", m1 ); - lo_message_free(m1); + hid_dev_desc * hid = hiddevices.find( joy_idx )->second; + if ( hid != NULL ){ + lo_message m1 = get_hid_info_msg( hid->info ); + lo_send_message_from( t, s, "/hid/info", m1 ); + lo_message_free(m1); + } else { + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/info/error", "i", joy_idx ); + } } int hid_info_handler(const char *path, const char *types, lo_arg **argv, int argc, @@ -328,28 +348,32 @@ int hid_info_handler(const char *path, const char *types, lo_arg **argv, int arg printf("hidapi2osc: joystick info handler\n"); send_hid_info( argv[0]->i ); + return 0; } -int hid_elements_info_handler(const char *path, const char *types, lo_arg **argv, int argc, +int hid_element_info_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { printf("hidapi2osc: joystick elements info handler\n"); send_elements_hid_info( argv[0]->i ); + return 0; } int hid_open_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { - printf("hidapi2osc: joystick open handler\n"); +// printf("hidapi2osc: joystick open handler\n"); open_device( argv[0]->i, argv[1]->i, NULL ); + return 0; } int hid_close_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { - printf("hidapi2osc: joystick close handler\n"); + printf("hidapi2osc: joystick close handler, %i\n", argv[0]->i ); close_device( argv[0]->i ); + return 0; } diff --git a/hidapi2osc/supercollider/hidapi2osc-test.scd b/hidapi2osc/supercollider/hidapi2osc-test.scd new file mode 100644 index 00000000..7d2ebe97 --- /dev/null +++ b/hidapi2osc/supercollider/hidapi2osc-test.scd @@ -0,0 +1,23 @@ +OSCFunc.trace( true ) +OSCFunc.trace( false ) + +OSCdef( \hidInfo, { |msg| msg.postln; }, '/hid/info' ); + +OSCdef( \elementInfo, { |msg| msg.postln; }, '/hid/element/info' ); +OSCdef( \elementNumber, { |msg| msg.postln; }, '/hid/element/number' ); + +// OSCdef( \elementData, { |msg| msg.postln; }, '/hid/element/data' ); + +n = NetAddr.new( "127.0.0.1", 57151 ); + +n.sendMsg( "/hidapi2osc/info" ); + +n.sendMsg( "/hid/open", 1103, 53251 ); + +n.sendMsg( "/hid/info", 0); + +n.sendMsg( "/hid/elements/info", 0); + +n.sendMsg( "/hid/close", 0); + +n.sendMsg( "/hidapi2osc/quit" ); \ No newline at end of file diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index 3684abd6..5777b15c 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -105,29 +105,29 @@ #define BITMASK1(n) ((1ULL << (n)) - 1ULL) -void hid_descriptor_init( hid_device_descriptor * devd){ +void hid_descriptor_init( struct hid_device_descriptor * devd){ hid_set_descriptor_callback(devd, NULL, NULL); hid_set_element_callback(devd, NULL, NULL); } -void hid_free_descriptor( hid_device_descriptor * devd){ +void hid_free_descriptor( struct hid_device_descriptor * devd){ free( devd ); // hid_set_descriptor_callback(devd, NULL, NULL); // hid_set_element_callback(devd, NULL, NULL); } -void hid_set_descriptor_callback( hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ){ +void hid_set_descriptor_callback( struct hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ){ devd->_descriptor_callback = cb; devd->_descriptor_data = user_data; } -void hid_set_element_callback( hid_device_descriptor * devd, hid_element_callback cb, void *user_data ){ +void hid_set_element_callback( struct hid_device_descriptor * devd, hid_element_callback cb, void *user_data ){ devd->_element_callback = cb; devd->_element_data = user_data; } -int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descriptor * descriptor ){ - hid_device_element * prev_element; +int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ){ + struct hid_device_element * prev_element; int current_usage_page; int current_usage; int current_usages[256]; @@ -278,7 +278,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 1; new_element->type = next_val; //TODO: parse this for more detailed info @@ -328,7 +328,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 2; new_element->type = next_val; //TODO: parse this for more detailed info @@ -378,7 +378,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 3; new_element->type = next_val; //TODO: parse this for more detailed info @@ -460,25 +460,25 @@ int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descripto return 0; } -float hid_element_map_logical( hid_device_element * element ){ +float hid_element_map_logical( struct hid_device_element * element ){ float result = element->logical_min + ( element->value/( element->logical_max - element->logical_min ) ); return result; } -float hid_element_resolution( hid_device_element * element ){ +float hid_element_resolution( struct hid_device_element * element ){ float result = 0; // ( element->logical_max - element->logical_min) / ( ( element->phys_max - element->phys_min) * pow(10, element->unit_exponent) ); return result; } -float hid_element_map_physical( hid_device_element * element ){ +float hid_element_map_physical( struct hid_device_element * element ){ float result = 0; return result; } -hid_device_element * hid_get_next_input_element( hid_device_element * curel ){ +struct hid_device_element * hid_get_next_input_element( struct hid_device_element * curel ){ - hid_device_element * nextel = curel->next; + struct hid_device_element * nextel = curel->next; while ( nextel != NULL ){ if ( nextel->io_type == 1 ){ return nextel; @@ -490,11 +490,11 @@ hid_device_element * hid_get_next_input_element( hid_device_element * curel ){ // is NULL } -int hid_parse_input_report( unsigned char* buf, int size, hid_device_descriptor * descriptor ){ +int hid_parse_input_report( unsigned char* buf, int size, struct hid_device_descriptor * descriptor ){ ///TODO: parse input from descriptors with report size like 12 correctly // Print out the returned buffer. - hid_device_element * cur_element = descriptor->first; + struct hid_device_element * cur_element = descriptor->first; int i; int next_byte_size; int next_mod_bit_size; @@ -600,8 +600,8 @@ int hid_parse_input_report( unsigned char* buf, int size, hid_device_descriptor -hid_device_descriptor * hid_read_descriptor( hid_device * devd ){ - hid_device_descriptor * descriptor; +struct hid_device_descriptor * hid_read_descriptor( hid_device * devd ){ + struct hid_device_descriptor * descriptor; unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; int res; res = hid_get_report_descriptor( devd, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); @@ -609,24 +609,24 @@ hid_device_descriptor * hid_read_descriptor( hid_device * devd ){ printf("Unable to read report descriptor\n"); return NULL; } else { - descriptor = (hid_device_descriptor *) malloc( sizeof( hid_device_descriptor) ); + descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); hid_descriptor_init( descriptor ); hid_parse_report_descriptor( descr_buf, res, descriptor ); return descriptor; } } -hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number ){ +struct hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number ){ hid_device * handle = hid_open( vendor, product, serial_number ); if (!handle){ return NULL; } - hid_device_descriptor * newdesc = hid_read_descriptor( handle ); + struct hid_device_descriptor * newdesc = hid_read_descriptor( handle ); if ( newdesc == NULL ){ hid_close( handle ); return NULL; } - hid_dev_desc * newdevdesc = (hid_dev_desc *) malloc( sizeof( hid_dev_desc ) ); + struct hid_dev_desc * newdevdesc = (struct hid_dev_desc *) malloc( sizeof( struct hid_dev_desc ) ); struct hid_device_info * newinfo = hid_enumerate(vendor,product); newdevdesc->device = handle; //TODO: if serial_number is given, the info descriptor should also point to that one! @@ -639,7 +639,7 @@ hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, return newdevdesc; } -void hid_close_device( hid_dev_desc * devdesc ){ +void hid_close_device( struct hid_dev_desc * devdesc ){ hid_close( devdesc->device ); hid_free_enumeration( devdesc->info ); hid_free_descriptor( devdesc->descriptor ); diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 7430109b..7b23bbf2 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -4,17 +4,25 @@ #define HIDAPI_MAX_DESCRIPTOR_SIZE 4096 +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + #include + +// typedef struct _hid_device_element hid_device_element; +// typedef struct _hid_device_descriptor hid_device_descriptor; +// typedef struct _hid_dev_desc hid_dev_desc; -typedef struct _hid_device_element hid_device_element; -typedef struct _hid_device_descriptor hid_device_descriptor; -typedef struct _hid_dev_desc hid_dev_desc; +struct hid_device_element; +struct hid_device_descriptor; +struct hid_dev_desc; // struct hid_element_cb; // struct hid_descriptor_cb; -typedef void (*hid_element_callback) ( hid_device_element *element, void *user_data); -typedef void (*hid_descriptor_callback) ( hid_device_descriptor *descriptor, void *user_data); +typedef void (*hid_element_callback) ( struct hid_device_element *element, void *user_data); +typedef void (*hid_descriptor_callback) ( struct hid_device_descriptor *descriptor, void *user_data); // typedef struct _hid_element_cb { // hid_element_callback cb; @@ -26,14 +34,14 @@ typedef void (*hid_descriptor_callback) ( hid_device_descriptor *descriptor, voi // void *data; // } hid_descriptor_cb; -struct _hid_dev_desc { +struct hid_dev_desc { int index; hid_device *device; - hid_device_descriptor *descriptor; - struct hid_device_info *info; + struct hid_device_descriptor *descriptor; + struct hid_device_info *info; }; -struct _hid_device_element { +struct hid_device_element { int index; int io_type; // input(1), output(2), feature(3) @@ -58,14 +66,14 @@ struct _hid_device_element { int value; /** Pointer to the next element */ - hid_device_element *next; + struct hid_device_element *next; }; -struct _hid_device_descriptor { +struct hid_device_descriptor { int num_elements; /** Pointer to the first element */ - hid_device_element *first; + struct hid_device_element *first; /** pointers to callback function */ hid_element_callback _element_callback; @@ -74,29 +82,35 @@ struct _hid_device_descriptor { void *_descriptor_data; }; +// higher level functions: +struct hid_device_descriptor * hid_read_descriptor( hid_device *devd ); +struct hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number ); +extern void hid_close_device( struct hid_dev_desc * devdesc ); + + // typedef void (*event_cb_t)(const struct hid_device_element *element, void *user_data); -void hid_descriptor_init( hid_device_descriptor * devd); -void hid_free_descriptor( hid_device_descriptor * devd); +void hid_descriptor_init( struct hid_device_descriptor * devd); +void hid_free_descriptor( struct hid_device_descriptor * devd); -void hid_set_descriptor_callback( hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ); -void hid_set_element_callback( hid_device_descriptor * devd, hid_element_callback cb, void *user_data ); +void hid_set_descriptor_callback( struct hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ); +void hid_set_element_callback( struct hid_device_descriptor * devd, hid_element_callback cb, void *user_data ); -int hid_parse_report_descriptor( char* descr_buf, int size, hid_device_descriptor * descriptor ); +int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_descriptor * descriptor ); -hid_device_element * hid_get_next_input_element( hid_device_element * curel ); +struct hid_device_element * hid_get_next_input_element( struct hid_device_element * curel ); -int hid_parse_input_report( unsigned char* buf, int size, hid_device_descriptor * descriptor ); +int hid_parse_input_report( unsigned char* buf, int size, struct hid_device_descriptor * descriptor ); -float hid_element_resolution( hid_device_element * element ); -float hid_element_map_logical( hid_device_element * element ); -float hid_element_map_physical( hid_device_element * element ); +float hid_element_resolution( struct hid_device_element * element ); +float hid_element_map_logical( struct hid_device_element * element ); +float hid_element_map_physical( struct hid_device_element * element ); // int hid_parse_feature_report( char* buf, int size, hid_device_descriptor * descriptor ); -// higher level functions: -hid_device_descriptor * hid_read_descriptor( hid_device * devd ); -hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number ); -void hid_close_device( hid_dev_desc * devdesc ); +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif #endif + diff --git a/hidapi_parser/main.c b/hidapi_parser/main.c index 811285e5..7545e7fe 100644 --- a/hidapi_parser/main.c +++ b/hidapi_parser/main.c @@ -38,7 +38,7 @@ void list_devices( void ){ #define MAX_STR 255 -void print_element_info( hid_device_element *element ){ +void print_element_info( struct hid_device_element *element ){ printf( "index: %i, usage_page: %i, usage: %i, iotype: %i, type: %i, \n \ \tlogical_min: %i, logical_max: %i, \n \ @@ -85,14 +85,14 @@ void print_device_info( hid_device *handle ){ printf("Indexed String 1: %ls\n", wstr); } -static void my_element_cb(const hid_device_element *el, void *data) +static void my_element_cb(const struct hid_device_element *el, void *data) { printf("in %s\t", __func__); printf("element: usage %i, value %i, index %i\t", el->usage, el->value, el->index ); printf("user_data: %s\n", (const char *)data); } -static void my_descriptor_cb(const hid_device_descriptor *dd, void *data) +static void my_descriptor_cb(const struct hid_device_descriptor *dd, void *data) { printf("in %s\t", __func__); // printf("element: usage %i, value %i, index %i\n", el->usage, el->value, el->index ); @@ -105,8 +105,9 @@ int main(int argc, char* argv[]){ unsigned char buf[256]; unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; - hid_device_descriptor *descriptor; - hid_device *handle; + struct hid_dev_desc *devdesc; +// struct hid_device_descriptor *descriptor; +// hid_device *handle; #ifdef WIN32 UNREFERENCED_PARAMETER(argc); @@ -117,20 +118,28 @@ int main(int argc, char* argv[]){ return -1; list_devices(); - handle = hid_open( 0x044f, 0xd003, NULL); - if (!handle) { - printf("unable to open device\n"); - return 1; + devdesc = hid_open_device( 0x044f, 0xd003, NULL ); + if (!devdesc){ + fprintf(stderr, "Unable to open device %d, %d\n", 0x044f, 0xd003 ); + return 1; } - print_device_info( handle ); +// handle = hid_open( 0x044f, 0xd003, NULL); +// if (!handle) { +// printf("unable to open device\n"); +// return 1; +// } +// print_device_info( handle ); + + print_device_info( devdesc->device ); char my_custom_data[40] = "Hello!"; - descriptor = hid_read_descriptor( handle ); - if ( descriptor == NULL ){ - printf("unable to read descriptor\n"); - return 1; - } +// descriptor = hid_read_descriptor( handle ); +// if ( descriptor == NULL ){ +// printf("unable to read descriptor\n"); +// return 1; +// } + // res = hid_get_report_descriptor( handle, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); // if (res < 0){ // printf("Unable to read report descriptor\n"); @@ -142,13 +151,13 @@ int main(int argc, char* argv[]){ // // } - hid_set_descriptor_callback( descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); - hid_set_element_callback( descriptor, (hid_element_callback) my_element_cb, my_custom_data ); + hid_set_descriptor_callback( devdesc->descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); + hid_set_element_callback( devdesc->descriptor, (hid_element_callback) my_element_cb, my_custom_data ); // Set the hid_read() function to be non-blocking. - hid_set_nonblocking(handle, 1); +// hid_set_nonblocking(handle, 1); - hid_device_element * cur_element = descriptor->first; + struct hid_device_element * cur_element = devdesc->descriptor->first; while (cur_element) { print_element_info( cur_element ); @@ -167,9 +176,9 @@ int main(int argc, char* argv[]){ // This loop demonstrates the non-blocking nature of hid_read(). res = 0; while (1) { - res = hid_read(handle, buf, sizeof(buf)); + res = hid_read(devdesc->device, buf, sizeof(buf)); if ( res > 0 ) { - hid_parse_input_report( buf, res, descriptor ); + hid_parse_input_report( buf, res, devdesc->descriptor ); } #ifdef WIN32 Sleep(500); @@ -178,7 +187,8 @@ int main(int argc, char* argv[]){ #endif } - hid_close(handle); + hid_close_device( devdesc ); +// hid_close(handle); /* Free static HIDAPI objects. */ hid_exit(); diff --git a/hidparsertest/hidparsertest.c b/hidparsertest/hidparsertest.c new file mode 100644 index 00000000..7545e7fe --- /dev/null +++ b/hidparsertest/hidparsertest.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include + +#include +#include "hidapi_parser.h" + + +// Headers needed for sleeping. +#ifdef _WIN32 + #include +#else + #include +#endif + +void list_devices( void ){ + struct hid_device_info *devs, *cur_dev; + devs = hid_enumerate(0x0, 0x0); + cur_dev = devs; + while (cur_dev) { + printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); + printf("\n"); + printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); + printf(" Product: %ls\n", cur_dev->product_string); + printf(" Release: %hx\n", cur_dev->release_number); + printf(" Interface: %d\n", cur_dev->interface_number); + printf("\n"); + cur_dev = cur_dev->next; + } + hid_free_enumeration(devs); +} + +// static hid_device * open_device( char vendor_id, char product_id ){ +// handle = +// return handle; +// } + +#define MAX_STR 255 + +void print_element_info( struct hid_device_element *element ){ + + printf( "index: %i, usage_page: %i, usage: %i, iotype: %i, type: %i, \n \ + \tlogical_min: %i, logical_max: %i, \n \ + \tphys_min: %i, phys_max: %i, unit_exponent: %i, unit: %i, \n \ + \treport_size: %i, report_id: %i, report_index: %i \n", + element->index, element->usage_page, element->usage, element->io_type, element->type, + element->logical_min, element->logical_max, + element->phys_min, element->phys_max, + element->unit_exponent, element->unit, + element->report_size, element->report_id, element->report_index ); + +} + +void print_device_info( hid_device *handle ){ + wchar_t wstr[MAX_STR]; + int res; + // Read the Manufacturer String + wstr[0] = 0x0000; + res = hid_get_manufacturer_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read manufacturer string\n"); + printf("Manufacturer String: %ls\n", wstr); + + // Read the Product String + wstr[0] = 0x0000; + res = hid_get_product_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read product string\n"); + printf("Product String: %ls\n", wstr); + + // Read the Serial Number String + wstr[0] = 0x0000; + res = hid_get_serial_number_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read serial number string\n"); + printf("Serial Number String: (%d) %ls", wstr[0], wstr); + printf("\n"); + + // Read Indexed String 1 + wstr[0] = 0x0000; + res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); + if (res < 0) + printf("Unable to read indexed string 1\n"); + printf("Indexed String 1: %ls\n", wstr); +} + +static void my_element_cb(const struct hid_device_element *el, void *data) +{ + printf("in %s\t", __func__); + printf("element: usage %i, value %i, index %i\t", el->usage, el->value, el->index ); + printf("user_data: %s\n", (const char *)data); +} + +static void my_descriptor_cb(const struct hid_device_descriptor *dd, void *data) +{ + printf("in %s\t", __func__); +// printf("element: usage %i, value %i, index %i\n", el->usage, el->value, el->index ); + printf("user_data: %s\n", (const char *)data); +} + +int main(int argc, char* argv[]){ + + int res; + unsigned char buf[256]; + unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; + + struct hid_dev_desc *devdesc; +// struct hid_device_descriptor *descriptor; +// hid_device *handle; + +#ifdef WIN32 + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); +#endif + + if (hid_init()) + return -1; + list_devices(); + + devdesc = hid_open_device( 0x044f, 0xd003, NULL ); + if (!devdesc){ + fprintf(stderr, "Unable to open device %d, %d\n", 0x044f, 0xd003 ); + return 1; + } +// handle = hid_open( 0x044f, 0xd003, NULL); +// if (!handle) { +// printf("unable to open device\n"); +// return 1; +// } +// print_device_info( handle ); + + print_device_info( devdesc->device ); + + char my_custom_data[40] = "Hello!"; + +// descriptor = hid_read_descriptor( handle ); +// if ( descriptor == NULL ){ +// printf("unable to read descriptor\n"); +// return 1; +// } + +// res = hid_get_report_descriptor( handle, descr_buf, HIDAPI_MAX_DESCRIPTOR_SIZE ); +// if (res < 0){ +// printf("Unable to read report descriptor\n"); +// return 1; +// } else { +// descriptor = (hid_device_descriptor *) malloc( sizeof( hid_device_descriptor) ); +// hid_descriptor_init( descriptor ); +// hid_parse_report_descriptor( descr_buf, res, descriptor ); +// +// } + + hid_set_descriptor_callback( devdesc->descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); + hid_set_element_callback( devdesc->descriptor, (hid_element_callback) my_element_cb, my_custom_data ); + + // Set the hid_read() function to be non-blocking. +// hid_set_nonblocking(handle, 1); + + struct hid_device_element * cur_element = devdesc->descriptor->first; + + while (cur_element) { + print_element_info( cur_element ); + cur_element = cur_element->next; + } + +// Request state (cmd 0x81). The first byte is the report number (0x1). +// buf[0] = 0x1; +// buf[1] = 0x81; +// hid_write(handle, buf, 17); +// if (res < 0) +// printf("Unable to write() (2)\n"); + + // Read requested state. hid_read() has been set to be + // non-blocking by the call to hid_set_nonblocking() above. + // This loop demonstrates the non-blocking nature of hid_read(). + res = 0; + while (1) { + res = hid_read(devdesc->device, buf, sizeof(buf)); + if ( res > 0 ) { + hid_parse_input_report( buf, res, devdesc->descriptor ); + } + #ifdef WIN32 + Sleep(500); + #else + usleep(500*100); + #endif + } + + hid_close_device( devdesc ); +// hid_close(handle); + + /* Free static HIDAPI objects. */ + hid_exit(); + +#ifdef WIN32 + system("pause"); +#endif + + return 0; + +} \ No newline at end of file From 6188ee8c1573dada085dcc563e6e540f6d5fbfef Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 15:10:58 +0200 Subject: [PATCH 20/27] cmake build system --- CMakeLists.txt | 74 ++++++++++++++++++++ cmake_modules/FindIConv.cmake | 43 ++++++++++++ cmake_modules/FindPthreads.cmake | 104 +++++++++++++++++++++++++++++ cmake_modules/FindUDev.cmake | 53 +++++++++++++++ cmake_modules/Findlibusb-1.0.cmake | 98 +++++++++++++++++++++++++++ hidapi/CMakeLists.txt | 1 + hidapi2osc/CMakeLists.txt | 36 ++++++++++ hidapi_parser/CMakeLists.txt | 14 ++++ hidparsertest/CMakeLists.txt | 13 ++++ hidtest/CMakeLists.txt | 18 +++++ libusb/CMakeLists.txt | 32 +++++++++ linux/CMakeLists.txt | 20 ++++++ mac/CMakeLists.txt | 10 +++ windows/CMakeLists.txt | 3 + 14 files changed, 519 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake_modules/FindIConv.cmake create mode 100644 cmake_modules/FindPthreads.cmake create mode 100644 cmake_modules/FindUDev.cmake create mode 100644 cmake_modules/Findlibusb-1.0.cmake create mode 100644 hidapi/CMakeLists.txt create mode 100644 hidapi2osc/CMakeLists.txt create mode 100644 hidapi_parser/CMakeLists.txt create mode 100644 hidparsertest/CMakeLists.txt create mode 100644 hidtest/CMakeLists.txt create mode 100644 libusb/CMakeLists.txt create mode 100644 linux/CMakeLists.txt create mode 100644 mac/CMakeLists.txt create mode 100644 windows/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..000dad4b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,74 @@ +cmake_minimum_required(VERSION 2.8) + +project(hidapi) + +set(VERSION_MAJOR "0") +set(VERSION_MINOR "7") +set(VERSION_PATCH "1") +set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") + + +option(DEBUG_PARSER "verbose parser debuggint output" OFF) + +option(LIBUSB "use libusb backend" OFF) +option(HIDRAW "use hidraw backend (linux/freebsd)" ON) + +option(EXAMPLE_TEST "build test example" ON) +option(EXAMPLE_OSC "build osc example" ON) + + +# add our own cmake-modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/") + +if( DEBUG_PARSER ) + add_definitions( -DDEBUG_PARSER ) +endif() + +# some default libraries +if (NOT WIN32) + find_package(Pthreads) + if (NOT PTHREADS_FOUND) + message(SEND_ERROR "cannot find libpthreads") + endif() +endif() + + +# directories +add_subdirectory(hidapi) + +if(LIBUSB) + add_subdirectory(libusb) +# set( hidapi_source ${hidapi_SOURCE_DIR}/libusb ) + link_directories( ${LIBUSB_1_LIBRARIES} ${PTHREADS_LIBRARIES} ) +endif() + +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND HIDRAW) + add_subdirectory(linux) +# set( hidapi_source ${hidapi_SOURCE_DIR}/linux ) + link_directories( ${UDEV_LIBRARIES} ) +endif() + +if(WIN32) + add_subdirectory(windows) +# set( hidapi_source ${hidapi_SOURCE_DIR}/windows ) + #todo: add library dependencies +endif() +if(APPLE) + add_subdirectory(mac) +# set( hidapi_source ${hidapi_SOURCE_DIR}/mac ) + #todo: add library dependencies - TEST + link_directories("-framework IOKit -framework CoreFoundation") +endif() + +add_subdirectory(hidapi_parser) + +# message( "main: hidapi source dir: ${hidapi_source}" ) + +if( EXAMPLE_TEST ) + add_subdirectory(hidtest) + add_subdirectory(hidparsertest) +endif() + +if( EXAMPLE_OSC ) + add_subdirectory(hidapi2osc) +endif() \ No newline at end of file diff --git a/cmake_modules/FindIConv.cmake b/cmake_modules/FindIConv.cmake new file mode 100644 index 00000000..76f27696 --- /dev/null +++ b/cmake_modules/FindIConv.cmake @@ -0,0 +1,43 @@ +# Find iconv library +# +# Author: Eddy Xu +# +# Released under BSD license +# +# ICONV_INCLUDE_DIRS - where to find iconv.h, etc +# ICONV_LIBRARIES - Lists of libraries when using iconv +# ICONV_FOUND - True if iconv found + + +# Look for the header file +FIND_PATH( ICONV_INCLUDE_DIR NAMES iconv.h ) +MARK_AS_ADVANCED( ICONV_INCLUDE_DIR ) + +# Look for the library +FIND_LIBRARY( ICONV_LIBRARY NAMES iconv ) +MARK_AS_ADVANCED( ICONV_LIBRARY ) + +# Copy the result to output variables +IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARY) + SET(ICONV_FOUND 1) + SET(ICONV_LIBRARIES ${ICONV_LIBRARY}) + SET(ICONV_INCLUDE_DIRS ${ICONV_INCLUDE_DIR}) +ELSE(ICONV_INCLUDE_DIR AND ICONV_LIBRARY) + SET(ICONV_FOUND 0) + SET(ICONV_LIBRARIES) + SET(ICONV_INCLUDE_DIRS) +ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARY) + +# Report results +IF(NOT ICONV_FOUND) + SET(ICONV_DIR_MESSAGE + "Iconv was not found. Make sure ICONV_LIBRARY and ICONV_INCLUDE_DIR are +set.") + IF(NOT ICONV_FIND_QUIETLY) + MESSAGE(STATUS ${ICONV_DIR_MESSAGE}) + ELSE(NOT ICONV_FIND_QUIETLY) + IF(ICONV_FIND_REQUIRED) + MESSAGE(FETAL_ERROR ${ICONV_DIR_MESSAGE}) + ENDIF(ICONV_FIND_REQUIRED) + ENDIF(NOT ICONV_FIND_QUIETLY) +ENDIF(NOT ICONV_FOUND) diff --git a/cmake_modules/FindPthreads.cmake b/cmake_modules/FindPthreads.cmake new file mode 100644 index 00000000..1b5683c5 --- /dev/null +++ b/cmake_modules/FindPthreads.cmake @@ -0,0 +1,104 @@ +# - Find the Pthreads library +# This module searches for the Pthreads library (including the +# pthreads-win32 port). +# +# This module defines these variables: +# +# PTHREADS_FOUND +# True if the Pthreads library was found +# PTHREADS_LIBRARY +# The location of the Pthreads library +# PTHREADS_INCLUDE_DIR +# The include directory of the Pthreads library +# PTHREADS_DEFINITIONS +# Preprocessor definitions to define (HAVE_PTHREAD_H is a fairly common +# one) +# +# This module responds to the PTHREADS_EXCEPTION_SCHEME +# variable on Win32 to allow the user to control the +# library linked against. The Pthreads-win32 port +# provides the ability to link against a version of the +# library with exception handling. IT IS NOT RECOMMENDED +# THAT YOU CHANGE PTHREADS_EXCEPTION_SCHEME TO ANYTHING OTHER THAN +# "C" because most POSIX thread implementations do not support stack +# unwinding. +# +# PTHREADS_EXCEPTION_SCHEME +# C = no exceptions (default) +# (NOTE: This is the default scheme on most POSIX thread +# implementations and what you should probably be using) +# CE = C++ Exception Handling +# SE = Structure Exception Handling (MSVC only) +# + +# +# Define a default exception scheme to link against +# and validate user choice. +# + +IF(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY) + SET(PTHREADS_DEFINITIONS -DHAVE_PTHREAD_H) + SET(PTHREADS_INCLUDE_DIRS ${PTHREADS_INCLUDE_DIR}) + SET(PTHREADS_LIBRARIES ${PTHREADS_LIBRARY}) + SET(FOUND_PTHREADS TRUE) +ENDIF() + +IF(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) + # Assign default if needed + SET(PTHREADS_EXCEPTION_SCHEME "C") +ELSE(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) + # Validate + IF(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + + MESSAGE(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed") + + ENDIF(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + + IF(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + MESSAGE(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC") + ENDIF(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + +ENDIF(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) + +# +# Find the header file +# +FIND_PATH(PTHREADS_INCLUDE_DIR pthread.h) + +# +# Find the library +# +SET(names) +IF(MSVC) + SET(names + pthreadV${PTHREADS_EXCEPTION_SCHEME}2 + pthread + ) +ELSEIF(MINGW) + SET(names + pthreadG${PTHREADS_EXCEPTION_SCHEME}2 + pthread + ) +ELSE(MSVC) # Unix / Cygwin / Apple / Etc. + SET(names pthread) +ENDIF(MSVC) + +FIND_LIBRARY(PTHREADS_LIBRARY NAMES ${names} + DOC "The Portable Threads Library") + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Pthreads DEFAULT_MSG + PTHREADS_LIBRARY PTHREADS_INCLUDE_DIR) + +IF(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY) + SET(PTHREADS_DEFINITIONS -DHAVE_PTHREAD_H) + SET(PTHREADS_INCLUDE_DIRS ${PTHREADS_INCLUDE_DIR}) + SET(PTHREADS_LIBRARIES ${PTHREADS_LIBRARY}) +ENDIF(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY) + +MARK_AS_ADVANCED(PTHREADS_INCLUDE_DIR) +MARK_AS_ADVANCED(PTHREADS_LIBRARY) diff --git a/cmake_modules/FindUDev.cmake b/cmake_modules/FindUDev.cmake new file mode 100644 index 00000000..9d68dda6 --- /dev/null +++ b/cmake_modules/FindUDev.cmake @@ -0,0 +1,53 @@ +# razor-de: Configure libudev environment +# +# UDEV_FOUND - system has a libudev +# UDEV_INCLUDE_DIR - where to find header files +# UDEV_LIBRARIES - the libraries to link against udev +# UDEV_STABLE - it's true when is the version greater or equals to 143 - version when the libudev was stabilized in its API +# +# copyright (c) 2011 Petr Vanek +# Redistribution and use is allowed according to the terms of the BSD license. +# + +FIND_PATH( + UDEV_INCLUDE_DIR + libudev.h + /usr/include + /usr/local/include + ${UDEV_PATH_INCLUDES} +) + +FIND_LIBRARY( + UDEV_LIBRARIES + NAMES udev libudev + PATHS + /usr/lib${LIB_SUFFIX} + /usr/local/lib${LIB_SUFFIX} + ${UDEV_PATH_LIB} +) + +IF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) + SET(UDEV_FOUND "YES") + execute_process(COMMAND pkg-config --atleast-version=143 libudev RESULT_VARIABLE UDEV_STABLE) + # retvale is 0 of the condition is "true" so we need to negate the value... + if (UDEV_STABLE) + set(UDEV_STABLE 0) + else (UDEV_STABLE) + set(UDEV_STABLE 1) + endif (UDEV_STABLE) + message(STATUS "libudev stable: ${UDEV_STABLE}") +ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) + +IF (UDEV_FOUND) + MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}") + MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}") +ELSE (UDEV_FOUND) + MESSAGE(STATUS "UDev not found.") + MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include") + MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}") + MESSAGE(STATUS "UDev: You can specify libs: -DUDEV_PATH_LIB=/opt/udev/lib") + MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}") + IF (UDev_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find UDev library") + ENDIF (UDev_FIND_REQUIRED) +ENDIF (UDEV_FOUND) \ No newline at end of file diff --git a/cmake_modules/Findlibusb-1.0.cmake b/cmake_modules/Findlibusb-1.0.cmake new file mode 100644 index 00000000..405ed516 --- /dev/null +++ b/cmake_modules/Findlibusb-1.0.cmake @@ -0,0 +1,98 @@ +# - Try to find libusb-1.0 +# Once done this will define +# +# LIBUSB_1_FOUND - system has libusb +# LIBUSB_1_INCLUDE_DIRS - the libusb include directory +# LIBUSB_1_LIBRARIES - Link these to use libusb +# LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb +# +# Adapted from cmake-modules Google Code project +# +# Copyright (c) 2006 Andreas Schneider +# +# (Changes for libusb) Copyright (c) 2008 Kyle Machulis +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# +# CMake-Modules Project New BSD License +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of the CMake-Modules Project nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) + # in cache already + set(LIBUSB_FOUND TRUE) +else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) + find_path(LIBUSB_1_INCLUDE_DIR + NAMES + libusb-1.0/libusb.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + PATH_SUFFIXES + libusb-1.0 + ) + + find_library(LIBUSB_1_LIBRARY + NAMES + usb-1.0 + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + set(LIBUSB_1_INCLUDE_DIRS + ${LIBUSB_1_INCLUDE_DIR} + ) + set(LIBUSB_1_LIBRARIES + ${LIBUSB_1_LIBRARY} +) + + if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + set(LIBUSB_1_FOUND TRUE) + endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + + if (LIBUSB_1_FOUND) + if (NOT libusb_1_FIND_QUIETLY) + message(STATUS "Found libusb-1.0:") + message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") + message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") + endif (NOT libusb_1_FIND_QUIETLY) + else (LIBUSB_1_FOUND) + if (libusb_1_FIND_REQUIRED) + message(FATAL_ERROR "Could not find libusb") + endif (libusb_1_FIND_REQUIRED) + endif (LIBUSB_1_FOUND) + + # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view + mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) + +endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) \ No newline at end of file diff --git a/hidapi/CMakeLists.txt b/hidapi/CMakeLists.txt new file mode 100644 index 00000000..56136376 --- /dev/null +++ b/hidapi/CMakeLists.txt @@ -0,0 +1 @@ +message( "hidapi cmakelists" ) \ No newline at end of file diff --git a/hidapi2osc/CMakeLists.txt b/hidapi2osc/CMakeLists.txt new file mode 100644 index 00000000..2a45a1da --- /dev/null +++ b/hidapi2osc/CMakeLists.txt @@ -0,0 +1,36 @@ +message( "===hidapi2osc cmakelists===" ) + +include(FindPkgConfig) +# pkg_check_modules +pkg_check_modules(liblo REQUIRED liblo) + +# add_subdirectory( ${hidapi_source} ) + +# message( "osc: hidapi include dirs are: ${hidapi_INCLUDE_DIRS}" ) +# message( "osc: hidapi parser include dirs are: ${hidapi_parser_INCLUDE_DIRS}" ) + +include_directories( + ${CMAKE_BINARY_DIR} + ${liblo_INCLUDE_DIRS} + ${hidapi_SOURCE_DIR}/hidapi/ + ${hidapi_SOURCE_DIR}/hidapi_parser/ +) + +link_directories( + ${liblo_LIBRARY_DIRS} +) + + +########################################################################## +# sdl2osc +########################################################################## + +set(hidapi2osc_SRCS + hidapi2osc.cpp +) + +add_executable( hidapi2osc ${hidapi2osc_SRCS} ) + +target_link_libraries(hidapi2osc ${liblo_LIBRARIES} hidapi hidapi_parser ) + +install(TARGETS hidapi2osc DESTINATION bin) \ No newline at end of file diff --git a/hidapi_parser/CMakeLists.txt b/hidapi_parser/CMakeLists.txt new file mode 100644 index 00000000..6ff107c7 --- /dev/null +++ b/hidapi_parser/CMakeLists.txt @@ -0,0 +1,14 @@ +message( "===hidapi_parser cmakelists===" ) + + +# message( "hidapi parser source dir is: ${hidapi_SOURCE_DIR}" ) +# +# set( hidapi_parser_INCLUDE_DIRS ${hidapi_SOURCE_DIR}/hidapi_parser/) +# # set( hidapi_LIBS ${UDEV_LIBRARIES}) +# set( hidapi_parser_SRCS hidapi_parser.c ) +# +# message( "hidapi_parser include dirs are: ${hidapi_parser_INCLUDE_DIRS}" ) + +include_directories( ${hidapi_SOURCE_DIR}/hidapi/ ) +add_library( hidapi_parser STATIC hidapi_parser.c ) +target_link_libraries( hidapi ) \ No newline at end of file diff --git a/hidparsertest/CMakeLists.txt b/hidparsertest/CMakeLists.txt new file mode 100644 index 00000000..367426b2 --- /dev/null +++ b/hidparsertest/CMakeLists.txt @@ -0,0 +1,13 @@ +message( "===hidparsertest cmakelists===" ) + +include_directories( + ${CMAKE_BINARY_DIR} + ${hidapi_SOURCE_DIR}/hidapi/ + ${hidapi_SOURCE_DIR}/hidapi_parser/ +) + +add_executable( hidparsertest hidparsertest.c ) + +target_link_libraries(hidparsertest hidapi hidapi_parser ) + +install(TARGETS hidparsertest DESTINATION bin) \ No newline at end of file diff --git a/hidtest/CMakeLists.txt b/hidtest/CMakeLists.txt new file mode 100644 index 00000000..75e71855 --- /dev/null +++ b/hidtest/CMakeLists.txt @@ -0,0 +1,18 @@ +message( "===hidtest cmakelists===" ) + +include_directories( + ${CMAKE_BINARY_DIR} + ${hidapi_SOURCE_DIR}/hidapi/ + ${hidapi_SOURCE_DIR}/hidapi_parser/ +) + + +set(hidtest_SRCS + hidtest.cpp +) + +add_executable( hidtest ${hidtest_SRCS} ) + +target_link_libraries(hidtest hidapi hidapi_parser ) + +install(TARGETS hidtest DESTINATION bin) \ No newline at end of file diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt new file mode 100644 index 00000000..5b2ee16c --- /dev/null +++ b/libusb/CMakeLists.txt @@ -0,0 +1,32 @@ +message( "===libusb cmakelists===" ) + + +#rt - clock_gettime +# may not be needed anymore, as of glibc 2.17 + +# include(CheckLibraryExists) +# CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_RT) + +# if( NOT HAVE_RT ) +# message( "--cannot find rt library" ) +# endif() + +# target_link_libraries( hid-usb -lrt) + +#libusb 1.0 + +find_package( libusb-1.0 ) + +## NOT TESTED: +IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + find_package( IConv ) +ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + +#TODO: ADD ICONV +# set( hidapi_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIRS} ${hidapi_SOURCE_DIR}/hidapi/ ${PTHREADS_INCLUDE_DIR}) +# set( hidapi_LIBS ${LIBUSB_1_LIBRARIES} ${PTHREADS_LIBRARIES}) +# set( hidapi_SRCS hid.c ) + +include_directories( ${LIBUSB_1_INCLUDE_DIRS} ${PTHREADS_INCLUDE_DIR} ${hidapi_SOURCE_DIR}/hidapi/ ) +add_library( hidapi STATIC hid.c ) +target_link_libraries( hidapi ${LIBUSB_1_LIBRARIES} ${PTHREADS_LIBRARIES} ) diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt new file mode 100644 index 00000000..b03febce --- /dev/null +++ b/linux/CMakeLists.txt @@ -0,0 +1,20 @@ +message( "===linux hidraw cmakelists===" ) + +#udev +find_package(UDev) + +# include_directories(${UDEV_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/hidapi/) +# link_libraries(${UDEV_LIBRARIES}) + +# message( "hidapi source dir is: ${hidapi_SOURCE_DIR}" ) + +# set( hidapi_INCLUDE_DIRS ${UDEV_INCLUDE_DIR} ${hidapi_SOURCE_DIR}/hidapi/) +# set( hidapi_LIBS ${UDEV_LIBRARIES}) +# set( hidapi_SRCS hid.c ) + +# message( "hidapi include dirs are: ${hidapi_INCLUDE_DIRS}" ) + +include_directories( ${UDEV_INCLUDE_DIR} ${hidapi_SOURCE_DIR}/hidapi/ ) +add_library( hidapi STATIC hid.c ) +target_link_libraries( hidapi ${UDEV_LIBRARIES} ) +# link_directories( hidapi ${UDEV_LIBRARIES} ) \ No newline at end of file diff --git a/mac/CMakeLists.txt b/mac/CMakeLists.txt new file mode 100644 index 00000000..48ae217b --- /dev/null +++ b/mac/CMakeLists.txt @@ -0,0 +1,10 @@ +message( "===mac cmakelists===" ) + +#pthreads +#-framework IOKit -framework CoreFoundation + +include_directories( ${UDEV_INCLUDE_DIR} ${hidapi_SOURCE_DIR}/hidapi/ ) +add_library( hidapi STATIC hid.c ) +# target_link_libraries( hidapi ${UDEV_LIBRARIES} ) + +target_link_libraries(hidapi "-framework IOKit -framework CoreFoundation") \ No newline at end of file diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 00000000..3545d7db --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,3 @@ +message( "===windows cmakelists===" ) + +# target_link_libraries( -lsetupapi ) \ No newline at end of file From ab9125e9a44b9278f5eb520925cdbb16544acc54 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 15:12:04 +0200 Subject: [PATCH 21/27] some fixes to initialisation and allocation --- hidapi2osc/hidapi2osc.cpp | 17 ++--------- hidapi_parser/hidapi_parser.c | 54 +++++++++++++++++++++++++++++------ hidapi_parser/hidapi_parser.h | 11 ++++--- hidparsertest/hidparsertest.c | 39 ++++++++++++++++++------- hidtest/hidtest.cpp | 2 ++ 5 files changed, 85 insertions(+), 38 deletions(-) diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index 78ce0a78..bdbe3c94 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -1,4 +1,4 @@ - +//TODO: add copyright notice #include // #include @@ -12,8 +12,6 @@ #include -// #include "../hidapi/hidapi.h" -// #include "../hidapi_parser/hidapi_parser.h" #include #include @@ -50,7 +48,7 @@ static void osc_element_cb( struct hid_device_element *el, void *data) lo_message_add_int32( m1, el->usage_page ); lo_message_add_int32( m1, el->usage ); lo_message_add_int32( m1, el->value ); -// lo_message_add_float( m1, hid_element_map_logical( el ) ); // TODO: this one is not found??? + lo_message_add_float( m1, hid_element_map_logical( el ) ); // TODO: this one is not found??? lo_send_message_from( t, s, "/hid/element/data", m1 ); lo_message_free(m1); } @@ -481,17 +479,6 @@ int main(int argc, char** argv) exit(1); } - // FIXME: We don't need video, but without it SDL will fail to work in SDL_WaitEvent() -// if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) -// if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_EVENT | SDL_INIT_JOYSTICK) < 0) -// { -// fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); -// exit(1); -// } -// else -// { -// atexit(SDL_Quit); - if (argc == 2 && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)) { diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index 5777b15c..ccb97ff6 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -1,9 +1,12 @@ +//TODO: add copyright notice + #include #include // #include #include "hidapi_parser.h" +// SET IN CMAKE // #define DEBUG_PARSER //// ---------- HID descriptor parser @@ -105,12 +108,41 @@ #define BITMASK1(n) ((1ULL << (n)) - 1ULL) -void hid_descriptor_init( struct hid_device_descriptor * devd){ - hid_set_descriptor_callback(devd, NULL, NULL); - hid_set_element_callback(devd, NULL, NULL); +struct hid_device_descriptor * hid_new_descriptor(){ + struct hid_device_descriptor * descriptor; + descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); +// hid_descriptor_init( descriptor ); + + descriptor->first = NULL; + hid_set_descriptor_callback(descriptor, NULL, NULL); + hid_set_element_callback(descriptor, NULL, NULL); + return descriptor; +} + +struct hid_device_element * hid_new_element(){ + struct hid_device_element * element = (struct hid_device_element *) malloc( sizeof( struct hid_device_element ) ); + element->next = NULL; + return element; } +void hid_free_element( struct hid_device_element * ele ){ + free( ele ); +} + +// void hid_descriptor_init( struct hid_device_descriptor * devd){ +// devd->first = NULL; +// hid_set_descriptor_callback(devd, NULL, NULL); +// hid_set_element_callback(devd, NULL, NULL); +// } + void hid_free_descriptor( struct hid_device_descriptor * devd){ + struct hid_device_element * cur_element = devd->first; + struct hid_device_element * next_element; + while (cur_element != NULL ) { + next_element = cur_element->next; + free( cur_element ); + cur_element = next_element; + } free( devd ); // hid_set_descriptor_callback(devd, NULL, NULL); // hid_set_element_callback(devd, NULL, NULL); @@ -278,7 +310,8 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 1; new_element->type = next_val; //TODO: parse this for more detailed info @@ -328,7 +361,8 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 2; new_element->type = next_val; //TODO: parse this for more detailed info @@ -378,7 +412,8 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de #endif // add the elements for this report for ( j=0; jindex = descriptor->num_elements; new_element->io_type = 3; new_element->type = next_val; //TODO: parse this for more detailed info @@ -461,7 +496,7 @@ int hid_parse_report_descriptor( char* descr_buf, int size, struct hid_device_de } float hid_element_map_logical( struct hid_device_element * element ){ - float result = element->logical_min + ( element->value/( element->logical_max - element->logical_min ) ); + float result = (float) element->logical_min + ( (float) element->value/( (float) element->logical_max - (float) element->logical_min ) ); return result; } @@ -609,8 +644,9 @@ struct hid_device_descriptor * hid_read_descriptor( hid_device * devd ){ printf("Unable to read report descriptor\n"); return NULL; } else { - descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); - hid_descriptor_init( descriptor ); + descriptor = hid_new_descriptor(); +// descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); +// hid_descriptor_init( descriptor ); hid_parse_report_descriptor( descr_buf, res, descriptor ); return descriptor; } diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 7b23bbf2..9a7c4e29 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -1,3 +1,5 @@ +//TODO: add copyright notice + #ifndef HIDAPI_PARSER_H__ #define HIDAPI_PARSER_H__ @@ -87,11 +89,12 @@ struct hid_device_descriptor * hid_read_descriptor( hid_device *devd ); struct hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short product, const wchar_t *serial_number ); extern void hid_close_device( struct hid_dev_desc * devdesc ); - -// typedef void (*event_cb_t)(const struct hid_device_element *element, void *user_data); - -void hid_descriptor_init( struct hid_device_descriptor * devd); +struct hid_device_descriptor * hid_new_descriptor(); void hid_free_descriptor( struct hid_device_descriptor * devd); +struct hid_device_element * hid_new_element(); +void hid_free_element( struct hid_device_element * ele); + +// void hid_descriptor_init( struct hid_device_descriptor * devd); void hid_set_descriptor_callback( struct hid_device_descriptor * devd, hid_descriptor_callback cb, void *user_data ); void hid_set_element_callback( struct hid_device_descriptor * devd, hid_element_callback cb, void *user_data ); diff --git a/hidparsertest/hidparsertest.c b/hidparsertest/hidparsertest.c index 7545e7fe..e9aada61 100644 --- a/hidparsertest/hidparsertest.c +++ b/hidparsertest/hidparsertest.c @@ -2,6 +2,7 @@ #include #include #include +// #include #include #include "hidapi_parser.h" @@ -19,7 +20,7 @@ void list_devices( void ){ devs = hid_enumerate(0x0, 0x0); cur_dev = devs; while (cur_dev) { - printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); + printf("Device Found\n type: 0x%04hx 0x%04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); printf("\n"); printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); printf(" Product: %ls\n", cur_dev->product_string); @@ -49,7 +50,6 @@ void print_element_info( struct hid_device_element *element ){ element->phys_min, element->phys_max, element->unit_exponent, element->unit, element->report_size, element->report_id, element->report_index ); - } void print_device_info( hid_device *handle ){ @@ -104,7 +104,7 @@ int main(int argc, char* argv[]){ int res; unsigned char buf[256]; unsigned char descr_buf[HIDAPI_MAX_DESCRIPTOR_SIZE]; - + struct hid_dev_desc *devdesc; // struct hid_device_descriptor *descriptor; // hid_device *handle; @@ -117,6 +117,19 @@ int main(int argc, char* argv[]){ if (hid_init()) return -1; list_devices(); + + int vendor_id; + int product_id; + + if (argc == 3 ){ + vendor_id = atoi( argv[1] ); + product_id = atoi( argv[1] ); + } else { + printf( "please run again with vendor and product id to open specified device, e.g. hidparsertest 0x044f 0xd003\n" ); + return 0; + } + printf( "vendor %i, product %i", vendor_id, product_id ); + devdesc = hid_open_device( 0x044f, 0xd003, NULL ); if (!devdesc){ @@ -131,9 +144,7 @@ int main(int argc, char* argv[]){ // print_device_info( handle ); print_device_info( devdesc->device ); - - char my_custom_data[40] = "Hello!"; - + // descriptor = hid_read_descriptor( handle ); // if ( descriptor == NULL ){ // printf("unable to read descriptor\n"); @@ -151,19 +162,27 @@ int main(int argc, char* argv[]){ // // } - hid_set_descriptor_callback( devdesc->descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); - hid_set_element_callback( devdesc->descriptor, (hid_element_callback) my_element_cb, my_custom_data ); - // Set the hid_read() function to be non-blocking. // hid_set_nonblocking(handle, 1); struct hid_device_element * cur_element = devdesc->descriptor->first; - while (cur_element) { + printf( "number of elements in device: %i\n", devdesc->descriptor->num_elements ); + while (cur_element != NULL ) { + printf("cur_element %i\n", cur_element ); print_element_info( cur_element ); +// printf("press key to continue\n" ); +// getchar(); cur_element = cur_element->next; } + printf("press key to continue\n" ); + getchar(); + + char my_custom_data[40] = "Hello!"; + hid_set_descriptor_callback( devdesc->descriptor, (hid_descriptor_callback) my_descriptor_cb, my_custom_data ); + hid_set_element_callback( devdesc->descriptor, (hid_element_callback) my_element_cb, my_custom_data ); + // Request state (cmd 0x81). The first byte is the report number (0x1). // buf[0] = 0x1; // buf[1] = 0x81; diff --git a/hidtest/hidtest.cpp b/hidtest/hidtest.cpp index 1839c0e8..9a9135e7 100644 --- a/hidtest/hidtest.cpp +++ b/hidtest/hidtest.cpp @@ -14,6 +14,8 @@ which use HIDAPI. ********************************************************/ +//TODO: add copyright notice + #include #include #include From aee4b90f4d943127417c71558379c6f9c0417907 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 15:19:27 +0200 Subject: [PATCH 22/27] add copyright notices --- hidapi2osc/hidapi2osc.cpp | 24 +++++++++++++++++++++++- hidapi_parser/hidapi_parser.c | 24 +++++++++++++++++++++++- hidapi_parser/hidapi_parser.h | 24 +++++++++++++++++++++++- hidparsertest/hidparsertest.c | 24 ++++++++++++++++++++++++ hidtest/hidtest.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 3 deletions(-) diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index bdbe3c94..d9de24a8 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -1,4 +1,26 @@ -//TODO: add copyright notice +/* hidapi_parser $ + * + * Copyright (C) 2013, Marije Baalman + * This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation + * including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway + * + * [1] http://supercollider.sourceforge.net + * [2] http://www.bek.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include // #include diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index ccb97ff6..3eedfb6d 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -1,4 +1,26 @@ -//TODO: add copyright notice +/* hidapi_parser $ + * + * Copyright (C) 2013, Marije Baalman + * This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation + * including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway + * + * [1] http://supercollider.sourceforge.net + * [2] http://www.bek.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include #include diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 9a7c4e29..0dbd216f 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -1,4 +1,26 @@ -//TODO: add copyright notice +/* hidapi_parser $ + * + * Copyright (C) 2013, Marije Baalman + * This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation + * including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway + * + * [1] http://supercollider.sourceforge.net + * [2] http://www.bek.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #ifndef HIDAPI_PARSER_H__ #define HIDAPI_PARSER_H__ diff --git a/hidparsertest/hidparsertest.c b/hidparsertest/hidparsertest.c index e9aada61..19106bf5 100644 --- a/hidparsertest/hidparsertest.c +++ b/hidparsertest/hidparsertest.c @@ -1,3 +1,27 @@ +/* hidapi_parser $ + * + * Copyright (C) 2013, Marije Baalman + * This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation + * including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway + * + * [1] http://supercollider.sourceforge.net + * [2] http://www.bek.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include #include #include diff --git a/hidtest/hidtest.cpp b/hidtest/hidtest.cpp index 9a9135e7..2f8aa982 100644 --- a/hidtest/hidtest.cpp +++ b/hidtest/hidtest.cpp @@ -1,3 +1,27 @@ +/* hidapi_parser $ + * + * Copyright (C) 2013, Marije Baalman + * This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation + * including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway + * + * [1] http://supercollider.sourceforge.net + * [2] http://www.bek.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + /******************************************************* Windows HID simplification From ca24d2d79c75d72c74f7d9c6f794de73ce67cf4f Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 15:41:26 +0200 Subject: [PATCH 23/27] update readme --- README.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.txt b/README.txt index 9297fb6e..8c93f976 100644 --- a/README.txt +++ b/README.txt @@ -1,3 +1,34 @@ + HIDAPI + parser library for Windows, Linux, FreeBSD and Mac OS X + ========================================================= +This version [1] is an extension of the original HIDAPI library, based on Tony Roggs fork [2], +which reads the report descriptor of the device. + +The main addition is a parser which parses the retrieved report descriptor, populates a struct +with the element descriptors, and finally provides a data parsing function based on this. + +In addition, a CMake build system has been made. + +Some test examples are available: +* hidparsertest will list all devices and optionally open one, displaying the element information, and the incoming data +* hidapi2osc will send out the data via OSC (OpenSoundControl), and provides an OSC interface for listing, opening and closing devices (see the supercollider script for testing the interface) + +[1] https://github.com/sensestage/hidapi +[2] https://github.com/tonyrog/hidapi + +TODO: +- creating + sending output reports +- creating + sending/reading + parsing feature reports +- reading windows report descriptor +- cmake lists for OSX, Windows and FreeBSD + + + Copyright (C) 2013, Marije Baalman + This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation + including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway + + [1] http://supercollider.sourceforge.net + [2] http://www.bek.no + HIDAPI library for Windows, Linux, FreeBSD and Mac OS X ========================================================= From 5eb06f019765b10c177b493aa082532ec936de93 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 15:59:00 +0200 Subject: [PATCH 24/27] also send device id with element info message --- hidapi2osc/hidapi2osc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index d9de24a8..ff129e6d 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -230,9 +230,10 @@ lo_message get_hid_info_msg( struct hid_device_info * info ) return m1; } -lo_message get_hid_element_info_msg( hid_device_element * el ) +lo_message get_hid_element_info_msg( hid_device_element * el, int devid ) { lo_message m1 = lo_message_new(); + lo_message_add_int32( m1, devid ); lo_message_add_int32( m1, el->index ); lo_message_add_int32( m1, el->usage_page ); lo_message_add_int32( m1, el->usage ); @@ -339,7 +340,7 @@ void send_elements_hid_info(int joy_idx) hid_device_element * cur_element = hid->descriptor->first; while (cur_element) { - lo_message m2 = get_hid_element_info_msg( cur_element ); + lo_message m2 = get_hid_element_info_msg( cur_element, joy_idx ); lo_bundle_add_message( b, "/hid/element/info", m2 ); cur_element = cur_element->next; } From 535597ac84616c8d729aa0cfeb49798370272177 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Thu, 12 Sep 2013 16:05:09 +0200 Subject: [PATCH 25/27] clean up osc interface --- hidapi2osc/hidapi2osc.cpp | 4 ++-- hidapi2osc/supercollider/hidapi2osc-test.scd | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index ff129e6d..833b2323 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -166,7 +166,7 @@ int init_osc( char * ip, char *outport, char * port ){ lo_server_thread st = lo_server_thread_new(port, error); lo_server_thread_add_method(st, "/hid/open", "ii", hid_open_handler, NULL); - lo_server_thread_add_method(st, "/hid/elements/info", "i", hid_element_info_handler, NULL); + lo_server_thread_add_method(st, "/hid/element/info", "i", hid_element_info_handler, NULL); lo_server_thread_add_method(st, "/hid/info", "i", hid_info_handler, NULL); lo_server_thread_add_method(st, "/hid/close", "i", hid_close_handler, NULL); @@ -327,7 +327,7 @@ void send_elements_hid_info(int joy_idx) { hid_dev_desc * hid = hiddevices.find( joy_idx )->second; if ( hid == NULL ){ - lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/elements/info/error", "i", joy_idx ); + lo_send_from( t, s, LO_TT_IMMEDIATE, "/hid/element/info/error", "i", joy_idx ); return; } lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); diff --git a/hidapi2osc/supercollider/hidapi2osc-test.scd b/hidapi2osc/supercollider/hidapi2osc-test.scd index 7d2ebe97..d6a651d2 100644 --- a/hidapi2osc/supercollider/hidapi2osc-test.scd +++ b/hidapi2osc/supercollider/hidapi2osc-test.scd @@ -1,12 +1,26 @@ OSCFunc.trace( true ) OSCFunc.trace( false ) +OSCdef( \hidStarted, { |msg| msg.postln; }, '/hidapi2osc/started' ); +OSCdef( \hidQuit, { |msg| msg.postln; }, '/hidapi2osc/quit' ); + +OSCdef( \hidOpen, { |msg| msg.postln; }, '/hid/open' ); +OSCdef( \hidOpenError, { |msg| msg.postln; }, '/hid/open/error' ); +OSCdef( \hidClose, { |msg| msg.postln; }, '/hid/closed' ); +OSCdef( \hidCloseError, { |msg| msg.postln; }, '/hid/close/error' ); + +OSCdef( \hidNumber, { |msg| msg.postln; }, '/hid/number' ); OSCdef( \hidInfo, { |msg| msg.postln; }, '/hid/info' ); +OSCdef( \hidInfoError, { |msg| msg.postln; }, '/hid/info/error' ); + -OSCdef( \elementInfo, { |msg| msg.postln; }, '/hid/element/info' ); OSCdef( \elementNumber, { |msg| msg.postln; }, '/hid/element/number' ); +OSCdef( \elementInfo, { |msg| msg.postln; }, '/hid/element/info' ); +OSCdef( \elementInfoError, { |msg| msg.postln; }, '/hid/element/info/error' ); + -// OSCdef( \elementData, { |msg| msg.postln; }, '/hid/element/data' ); +OSCdef( \elementData, { |msg| msg.postln; }, '/hid/element/data' ); +OSCdef( \deviceData, { |msg| msg.postln; }, '/hid/device/data' ); n = NetAddr.new( "127.0.0.1", 57151 ); @@ -16,7 +30,7 @@ n.sendMsg( "/hid/open", 1103, 53251 ); n.sendMsg( "/hid/info", 0); -n.sendMsg( "/hid/elements/info", 0); +n.sendMsg( "/hid/element/info", 0); n.sendMsg( "/hid/close", 0); From 43fa4b0eb8bcb2487c137f94fecb53442b06f2eb Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Fri, 13 Sep 2013 11:39:25 +0200 Subject: [PATCH 26/27] update cmake list to work withing supercollider as submodule --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 000dad4b..82193921 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ option(EXAMPLE_OSC "build osc example" ON) # add our own cmake-modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake_modules/") if( DEBUG_PARSER ) add_definitions( -DDEBUG_PARSER ) From 14e63897bdf52b2c872e661a800d9bab3b95a167 Mon Sep 17 00:00:00 2001 From: Marije Baalman Date: Fri, 13 Sep 2013 11:39:40 +0200 Subject: [PATCH 27/27] move hid_init --- hidapi2osc/hidapi2osc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hidapi2osc/hidapi2osc.cpp b/hidapi2osc/hidapi2osc.cpp index 833b2323..33cfaff8 100644 --- a/hidapi2osc/hidapi2osc.cpp +++ b/hidapi2osc/hidapi2osc.cpp @@ -515,6 +515,8 @@ int main(int argc, char** argv) else if (argc == 2 && (strcmp(argv[1], "--list") == 0 || (strcmp(argv[1], "-l") == 0))) { + if (hid_init()) + return -1; list_devices(); } // else if (argc == 3 && (strcmp(argv[1], "--event") == 0 || @@ -556,10 +558,12 @@ int main(int argc, char** argv) init_osc( ip, outport, port ); + if (hid_init()) + return -1; + printf("Entering hid read loop, press Ctrl-c to exit\n"); int res = 0; - hid_map_t::const_iterator it; unsigned char buf[256]; while(!done){