From c5e8ee585df16dd45956368218ca20b66b4c8af7 Mon Sep 17 00:00:00 2001 From: Thibaud Date: Wed, 23 May 2018 01:25:02 +0200 Subject: [PATCH] Add files --- hidapi.h | 391 ++++++++++++++++++++++++++++++++++ lib/libhidapi-libusb.so | 1 + lib/libhidapi-libusb.so.0.0.0 | Bin 0 -> 75800 bytes main.c | 167 +++++++++++++++ spnav.c | 132 ++++++++++++ spnav.h | 56 +++++ 6 files changed, 747 insertions(+) create mode 100644 hidapi.h create mode 120000 lib/libhidapi-libusb.so create mode 100755 lib/libhidapi-libusb.so.0.0.0 create mode 100644 main.c create mode 100644 spnav.c create mode 100644 spnav.h diff --git a/hidapi.h b/hidapi.h new file mode 100644 index 0000000..e5bc2dc --- /dev/null +++ b/hidapi.h @@ -0,0 +1,391 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/** @file + * @defgroup API hidapi API + */ + +#ifndef HIDAPI_H__ +#define HIDAPI_H__ + +#include + +#ifdef _WIN32 + #define HID_API_EXPORT __declspec(dllexport) + #define HID_API_CALL +#else + #define HID_API_EXPORT /**< API export macro */ + #define HID_API_CALL /**< API call macro */ +#endif + +#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct hid_device_; + typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ + + /** hidapi info structure */ + struct hid_device_info { + /** Platform-specific device path */ + char *path; + /** Device Vendor ID */ + unsigned short vendor_id; + /** Device Product ID */ + unsigned short product_id; + /** Serial Number */ + wchar_t *serial_number; + /** Device Release Number in binary-coded decimal, + also known as Device Version Number */ + unsigned short release_number; + /** Manufacturer String */ + wchar_t *manufacturer_string; + /** Product string */ + wchar_t *product_string; + /** Usage Page for this Device/Interface + (Windows/Mac only). */ + unsigned short usage_page; + /** Usage for this Device/Interface + (Windows/Mac only).*/ + unsigned short usage; + /** The USB interface which this logical device + represents. Valid on both Linux implementations + in all cases, and valid on the Windows implementation + only if the device contains more than one interface. */ + int interface_number; + + /** Pointer to the next device */ + struct hid_device_info *next; + }; + + + /** @brief Initialize the HIDAPI library. + + This function initializes the HIDAPI library. Calling it is not + strictly necessary, as it will be called automatically by + hid_enumerate() and any of the hid_open_*() functions if it is + needed. This function should be called at the beginning of + execution however, if there is a chance of HIDAPI handles + being opened by different threads simultaneously. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_init(void); + + /** @brief Finalize the HIDAPI library. + + This function frees all of the static data associated with + HIDAPI. It should be called at the end of execution to avoid + memory leaks. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_exit(void); + + /** @brief Enumerate the HID Devices. + + This function returns a linked list of all the HID devices + attached to the system which match vendor_id and product_id. + If @p vendor_id is set to 0 then any vendor matches. + If @p product_id is set to 0 then any product matches. + If @p vendor_id and @p product_id are both set to 0, then + all HID devices will be returned. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the types of device + to open. + @param product_id The Product ID (PID) of the types of + device to open. + + @returns + This function returns a pointer to a linked list of type + struct #hid_device, containing information about the HID devices + attached to the system, or NULL in the case of failure. Free + this linked list by calling hid_free_enumeration(). + */ + struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); + + /** @brief Free an enumeration Linked List + + This function frees a linked list created by hid_enumerate(). + + @ingroup API + @param devs Pointer to a list of struct_device returned from + hid_enumerate(). + */ + void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); + + /** @brief Open a HID device using a Vendor ID (VID), Product ID + (PID) and optionally a serial number. + + If @p serial_number is NULL, the first device with the + specified VID and PID is opened. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the device to open. + @param product_id The Product ID (PID) of the device to open. + @param serial_number The Serial Number of the device to open + (Optionally NULL). + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); + + /** @brief Open a HID device by its path name. + + The path name be determined by calling hid_enumerate(), or a + platform-specific path name can be used (eg: /dev/hidraw0 on + Linux). + + @ingroup API + @param path The path name of the device to open + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); + + /** @brief Write an Output report to a HID device. + + The first byte of @p data[] must contain the Report ID. For + devices which only support a single report, this must be set + to 0x0. The remaining bytes contain the report data. Since + the Report ID is mandatory, calls to hid_write() will always + contain one more byte than the report contains. For example, + if a hid report is 16 bytes long, 17 bytes must be passed to + hid_write(), the Report ID (or 0x0, for devices with a + single report), followed by the report data (16 bytes). In + this example, the length passed in would be 17. + + hid_write() will send the data on the first OUT endpoint, if + one exists. If it does not, it will send the data through + the Control Endpoint (Endpoint 0). + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Read an Input report from a HID device with timeout. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + @param milliseconds timeout in milliseconds or -1 for blocking wait. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read within + the timeout period, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); + + /** @brief Read an Input report from a HID device. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read and + the handle is in non-blocking mode, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); + + /** @brief Set the device handle to be non-blocking. + + In non-blocking mode calls to hid_read() will return + immediately with a value of 0 if there is no data to be + read. In blocking mode, hid_read() will wait (block) until + there is data to read before returning. + + Nonblocking can be turned on and off at any time. + + @ingroup API + @param device A device handle returned from hid_open(). + @param nonblock enable or not the nonblocking reads + - 1 to enable nonblocking + - 0 to disable nonblocking. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); + + /** @brief Send a Feature report to the device. + + Feature reports are sent over the Control endpoint as a + Set_Report transfer. The first byte of @p data[] must + contain the Report ID. For devices which only support a + single report, this must be set to 0x0. The remaining bytes + contain the report data. Since the Report ID is mandatory, + calls to hid_send_feature_report() will always contain one + more byte than the report contains. For example, if a hid + report is 16 bytes long, 17 bytes must be passed to + hid_send_feature_report(): the Report ID (or 0x0, for + devices which do not use numbered reports), followed by the + report data (16 bytes). In this example, the length passed + in would be 17. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send, including + the report number. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Get a feature report from a HID device. + + Set the first byte of @p data[] to the Report ID of the + report to be read. Make sure to allow space for this + extra byte in @p data[]. Upon return, the first byte will + still contain the Report ID, and the report data will + start in data[1]. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read, or set it to zero + if your device does not use numbered reports. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read plus + one for the report ID (which is still in the first + byte), or -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); + + /** @brief Close a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + */ + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); + + /** @brief Get The Manufacturer String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Product String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Serial Number String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get a string from a HID device, based on its string index. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string_index The index of the string to get. + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); + + /** @brief Get a string describing the last error which occurred. + + @ingroup API + @param device A device handle returned from hid_open(). + + @returns + This function returns a string containing the last error + which occurred or NULL if none has occurred. + */ + HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib/libhidapi-libusb.so b/lib/libhidapi-libusb.so new file mode 120000 index 0000000..92e7ba1 --- /dev/null +++ b/lib/libhidapi-libusb.so @@ -0,0 +1 @@ +libhidapi-libusb.so.0.0.0 \ No newline at end of file diff --git a/lib/libhidapi-libusb.so.0.0.0 b/lib/libhidapi-libusb.so.0.0.0 new file mode 100755 index 0000000000000000000000000000000000000000..ac134c33a471d0a049f82089a928d6acc77518eb GIT binary patch literal 75800 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 literal 0 HcmV?d00001 diff --git a/main.c b/main.c new file mode 100644 index 0000000..6bfda88 --- /dev/null +++ b/main.c @@ -0,0 +1,167 @@ +#include +#include +#include + +#define MAX_STR 255 +#define SPNAV_VENDOR_ID 0x046d +#define SPNAV_PRODUCT_ID 0xc626 + +// enum { +// TRANSLATION = 1, +// ROTATION = 2, +// BUTTON = 3 +// }; + +// struct event_motion { +// int type; +// int x, y, z; +// int rx, ry, rz; +// unsigned int period; +// int *data; +// }; + +// struct event_button { +// int type; +// int press; +// int bnum; +// }; + +// typedef union spnav_event { +// int type; +// struct event_motion motion; +// struct event_button button; +// } spnav_event; + +// static bool INTERRUPTED = false; + +// int spnav_convert_input(int first, unsigned char val) { +// switch (val) { +// case 0: +// return first; +// case 1: +// return first + 255; +// case 254: +// return -512 + first; +// case 255: +// return -255 + first; +// default: +// return 0; +// } +// } + +// spnav_event read_event(hid_device *device, int ms) { +// spnav_event ev; +// unsigned char buf[64]; +// int nbytes = hid_read_timeout(device, buf, sizeof(buf), ms); +// if (nbytes < 0) { +// // TODO : error handling +// wprintf(L"error hid_read"); +// } else if (nbytes == 0) { +// ev.type = 0; +// } +// ev.type = buf[0]; + +// switch (ev.type) { +// case TRANSLATION: +// ev.type = 0; + +// ev.motion.x = spnav_convert_input((buf[1] & 0x0000ff), buf[2]); +// ev.motion.y = spnav_convert_input((buf[3] & 0x0000ff), buf[4]); +// ev.motion.z = spnav_convert_input((buf[5] & 0x0000ff), buf[6]); +// //wprintf(L"Translation x=%d, y=%d, z=%d\n", ev.motion.x, ev.motion.y, ev.motion.z); +// break; +// case ROTATION: +// ev.type = 1; +// ev.motion.rx = spnav_convert_input((buf[1] & 0x0000ff), buf[2]); +// ev.motion.ry = spnav_convert_input((buf[3] & 0x0000ff), buf[4]); +// ev.motion.rz = spnav_convert_input((buf[5] & 0x0000ff), buf[6]); +// //wprintf(L"Rotation rx=%d, ry=%d, rz=%d\n", ev.motion.rx, ev.motion.ry, ev.motion.rz); +// break; +// case BUTTON: +// wprintf(L"Buttons: %d %d\n", /* btn 1 */buf[1] & 0x01, /* btn 2 */ buf[1] & 0x02); +// break; +// } +// return ev; +// } + +// void set_led(hid_device *dev, char state) { +// const unsigned char led_data[2] = {0x04, state}; +// // led_data[0] = 0x04; +// // led_data[1] = state; +// int nbytes = hid_write(dev, led_data, sizeof(led_data)); +// wprintf(L"Bytes written : %d\n", nbytes); +// } + +// void spnav_stop(hid_device *dev) { +// set_led(dev, 0); +// hid_close(dev); +// hid_exit(); +// } + +// void sighandler(int signo) { +// if (signo == SIGINT) { +// wprintf(L"Stopping...\n"); +// INTERRUPTED = true; +// } +// } + +#include +#include +#include "spnav.h" + +static bool INTERRUPTED = false; + +void sighandler(int signo) { + if (signo == SIGINT) { + INTERRUPTED = true; + } +} + +int main(int argc, char const *argv[]) +{ + signal(SIGINT, sighandler); + /* + // Initialize the hidapi library + hid_init(); + // Open the device using the VID, PID, + // and optionally the Serial number. + hid_device *handle = hid_open(SPNAV_VENDOR_ID, SPNAV_PRODUCT_ID, NULL); + + set_led(handle, 1); + + while (1) { + spnav_event ev = read_event(handle, 400); + if (ev.type == 0) { + wprintf(L"x=%d y=%d z=%d rx=%d ry=%d rz=%d\n", + ev.motion.x, ev.motion.y, ev.motion.z, ev.motion.rx, ev.motion.ry, ev.motion.rz); + } else { + wprintf(L"ev.type : %d\n", ev.type); + } + + if (INTERRUPTED) { + break; + } + } + spnav_stop(handle); + return 0; + */ + spnav_event ev; + spnav_open(); + for (;;) { + spnav_wait_event(&ev); + + switch (ev.type) { + case MOTION: + printf("x=%d, y=%d, z=%d ", ev.motion.x, ev.motion.y, ev.motion.z); + printf("rx=%d, ry=%d, rz=%d\n", ev.motion.rx, ev.motion.ry, ev.motion.rz); + break; + case BUTTON: + break; + } + + if (INTERRUPTED) { + break; + } + } + spnav_close(); +} diff --git a/spnav.c b/spnav.c new file mode 100644 index 0000000..6fe798f --- /dev/null +++ b/spnav.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include "spnav.h" +#include "hidapi.h" + +#define DEBUG + +#ifdef DEBUG +#define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while( false ) +#else +#define DEBUG_PRINT(...) do{ } while ( false ) +#endif + +enum { + TRANSLATION = 1, + ROTATION = 2, + BTN = 3 +}; + +static bool IS_OPEN = false; +/* HID device for SpaceNavigator mouse */ +hid_device *device = NULL; + +int convert_input(int first, unsigned char val) { + switch (val) { + case 0: + return first; + case 1: + return first + 255; + case 254: + return -512 + first; + case 255: + return -255 + first; + default: + return 0; + } +} + +int read_event(hid_device *device, spnav_event* ev, int ms) { + unsigned char buf[64]; + int nbytes = hid_read_timeout(device, buf, sizeof(buf), ms); + if (nbytes < 0) { + DEBUG_PRINT("hid_read_timeout() error"); + return -1; + } else if (nbytes == 0) { + ev->type = 0; + return 0; + } + ev->type = buf[0]; + + switch (ev->type) { + case TRANSLATION: + ev->type = 1; + ev->motion.x = convert_input((buf[1] & 0x0000ff), buf[2]); + ev->motion.y = convert_input((buf[3] & 0x0000ff), buf[4]); + ev->motion.z = convert_input((buf[5] & 0x0000ff), buf[6]); + // DEBUG_PRINT("Translation x=%d, y=%d, z=%d\n", ev->motion.x, ev->motion.y, ev->motion.z); + break; + case ROTATION: + ev->type = 1; + ev->motion.rx = convert_input((buf[1] & 0x0000ff), buf[2]); + ev->motion.ry = convert_input((buf[3] & 0x0000ff), buf[4]); + ev->motion.rz = convert_input((buf[5] & 0x0000ff), buf[6]); + // DEBUG_PRINT("Rotation rx=%d, ry=%d, rz=%d\n", ev->motion.rx, ev->motion.ry, ev->motion.rz); + break; + case BTN: + ev->type = 2; + DEBUG_PRINT("Buttons: %d %d\n", /* btn 1 */buf[1] & 0x01, /* btn 2 */ buf[1] & 0x02); + break; + } + + return 0; +} + +int set_led(hid_device *dev, char state) { + const unsigned char led_data[2] = {0x04, state}; + int nbytes = hid_write(dev, led_data, sizeof(led_data)); + if (nbytes != sizeof(led_data)) { + DEBUG_PRINT("set_led(): hid_write() has written %d bytes (should be %ld)\n", + nbytes, sizeof(led_data)); + return -1; + } + return 0; +} + +int spnav_open() { + DEBUG_PRINT("spnav_open()\n"); + /* Connexion already opened */ + if (IS_OPEN) { + DEBUG_PRINT("Connexion already opened!\n"); + return -1; + } + // Initialize the hidapi library + hid_init(); + // Open the device using the VID, PID, + // and optionally the Serial number. + device = hid_open(SPNAV_VENDOR_ID, SPNAV_PRODUCT_ID, NULL); + if (device == NULL) { + DEBUG_PRINT("hid_open() failed!"); + return -1; + } + IS_OPEN = true; + set_led(device, 1); + return 0; +} + +int spnav_close() { + DEBUG_PRINT("spnav_close()\n"); + if (!IS_OPEN) { + return -1; + } + + set_led(device, 0); + hid_close(device); + hid_exit(); + IS_OPEN = false; + return 0; +} + +int spnav_wait_event(spnav_event *event) { + if (device == NULL) { + DEBUG_PRINT("spnav_wait_event(): device not connected.\n"); + return -1; + } + read_event(device, event, -1); + return 0; +} + +/* +int spnav_wait_event(spnav_event *event); +int spnav_poll_event(spnav_event *event, int timeout); */ \ No newline at end of file diff --git a/spnav.h b/spnav.h new file mode 100644 index 0000000..f9c4d66 --- /dev/null +++ b/spnav.h @@ -0,0 +1,56 @@ +#ifndef SPNAV_H__ +#define SPNAV_H__ + +#define SPNAV_VENDOR_ID 0x046d +#define SPNAV_PRODUCT_ID 0xc626 + +#ifdef _WIN32 + #define SPNAV_API_EXPORT __declspec(dllexport) + #define SPNAV_API_CALL +#else + #define SPNAV_API_EXPORT /**< API export macro */ + #define SPNAV_API_CALL /**< API call macro */ +#endif + +#define SPNAV_API_EXPORT_CALL SPNAV_API_EXPORT SPNAV_API_CALL /**< API export and call macro*/ + +enum event_type { + ANY, + MOTION, + BUTTON +}; + +struct event_motion { + int type; + int x, y, z; + int rx, ry, rz; + unsigned int period; + int *data; +}; + +struct event_button { + int type; + int press; + int bnum; +}; + +typedef union spnav_event { + int type; + struct event_motion motion; + struct event_button button; +} spnav_event; + +#ifdef __cplusplus +extern "C" { +#endif + +int SPNAV_API_EXPORT_CALL spnav_open(void); +int SPNAV_API_EXPORT_CALL spnav_close(void); +int SPNAV_API_EXPORT_CALL spnav_wait_event(spnav_event *event); +int SPNAV_API_EXPORT_CALL spnav_poll_event(spnav_event *event, int timeout); +//spnav_event SPNAV_API_EXPORT_CALL read_event(int timeout); + +#ifdef __cplusplus +} +#endif +#endif /* SPNAV_H__ */ \ No newline at end of file