hid_listen

master
Stefan Dorn 2016-06-13 23:33:38 +01:00
parent 79cdf4f1f3
commit 6a2057e1da
5 changed files with 900 additions and 0 deletions

1
hid_listen/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/hid_listen

68
hid_listen/Makefile Normal file
View File

@ -0,0 +1,68 @@
PROG = hid_listen
OS = LINUX
#OS = DARWIN
#OS = WINDOWS
ifeq ($(OS), LINUX)
TARGET = $(PROG)
CC = gcc
STRIP = strip
CFLAGS = -O2 -Wall -D$(OS)
LIBS =
else ifeq ($(OS), DARWIN)
TARGET = $(PROG)
CC = gcc
STRIP = strip
SDK = /Developer/SDKs/MacOSX10.5.sdk
CFLAGS = -O2 -Wall -isysroot $(SDK) -D$(OS) -arch ppc -arch i386
LIBS = -Xlinker -syslibroot -Xlinker $(SDK) -framework IOKit -framework CoreFoundation
else ifeq ($(OS), WINDOWS)
TARGET = $(PROG).exe
CC = i586-mingw32msvc-gcc
STRIP = i586-mingw32msvc-strip
WINDRES = i586-mingw32msvc-windres
CFLAGS = -O2 -Wall -D$(OS)
LIBS = -lhid -lsetupapi
KEY_SPC = ~/bin/cert/mykey.spc
KEY_PVK = ~/bin/cert/mykey.pvk
KEY_TS = http://timestamp.comodoca.com/authenticode
endif
MAKEFLAGS = --jobs=2
OBJS = hid_listen.o rawhid.o
all: $(TARGET)
$(PROG): $(OBJS)
gcc -o $(PROG) $(OBJS) $(LIBS)
$(STRIP) $(PROG)
$(PROG).app: $(PROG) Info.plist
mkdir -p $(PROG).app/Contents/MacOS
mkdir -p $(PROG).app/Contents/Resources/English.lproj
cp Info.plist $(PROG).app/Contents/
echo -n 'APPL????' > $(PROG).app/Contents/PkgInfo
cp $(PROG) $(PROG).app/Contents/MacOS/$(PROG)
cp icons/$(PROG).icns $(PROG).app/Contents/Resources/$(PROG).icns
touch $(PROG).app
$(PROG).dmg: $(PROG).app
hdiutil create -ov -srcfolder $(PROG).app $(PROG).dmg
$(PROG).exe: $(OBJS)
$(CC) $(OBJS) -o $(PROG).exe $(LIBS)
$(STRIP) $(PROG).exe
-signcode -spc $(KEY_SPC) -v $(KEY_PVK) -t $(KEY_TS) $(PROG).exe
resource.o: resource.rs icons/$(PROG).ico
$(WINDRES) -o resource.o resource.rs
clean:
rm -f *.o $(PROG) $(PROG).exe $(PROG).exe.bak $(PROG).dmg
rm -rf $(PROG).app

88
hid_listen/hid_listen.c Normal file
View File

@ -0,0 +1,88 @@
/* HID Listen, http://www.pjrc.com/teensy/hid_listen.html
* Listens (and prints) all communication received from a USB HID device,
* which is useful for view debug messages from the Teensy USB Board.
* Copyright 2008, PJRC.COM, LLC
*
* You may redistribute this program 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, see http://www.gnu.org/licenses/
*/
#include "rawhid.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
static void delay_ms(unsigned int msec);
int main(void) {
char buf[64], *in, *out;
rawhid_t *hid;
int num, count;
printf("Waiting for device:");
fflush(stdout);
while (1) {
hid = rawhid_open_only1(0, 0, 0xFF31, 0x0074);
if (hid == NULL) {
printf(".");
fflush(stdout);
delay_ms(1000);
continue;
}
printf("\nListening:\n");
while (1) {
num = rawhid_read(hid, buf, sizeof(buf), 200);
if (num < 0)
break;
if (num == 0)
continue;
in = out = buf;
for (count = 0; count < num; count++) {
if (*in) {
*out++ = *in;
}
in++;
}
count = out - buf;
// printf("read %d bytes, %d actual\n", num, count);
if (count) {
struct timeval tv;
time_t nowtime;
struct tm *nowtm;
char tmbuf[64];
gettimeofday(&tv, NULL);
nowtime = tv.tv_sec;
nowtm = localtime(&nowtime);
strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
printf("%s.%06ld ", tmbuf, tv.tv_usec);
num = fwrite(buf, 1, count, stdout);
fflush(stdout);
}
}
rawhid_close(hid);
printf("\nDevice disconnected.\nWaiting for new device:");
}
return 0;
}
#if (defined(WIN32) || defined(WINDOWS) || defined(__WINDOWS__))
#include <windows.h>
static void delay_ms(unsigned int msec) { Sleep(msec); }
#else
#include <unistd.h>
static void delay_ms(unsigned int msec) { usleep(msec * 1000); }
#endif

720
hid_listen/rawhid.c Normal file
View File

@ -0,0 +1,720 @@
/* Raw HID I/O Routines
* Copyright 2008, PJRC.COM, LLC
* paul@pjrc.com
*
* You may redistribute this program 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, see http://www.gnu.org/licenses/
*/
// This code will someday be turned into "librawhid", an easy-to-use
// and truly cross platform library for accessing HID reports. But
// there are many complexities not properly handled by this simple
// code that would be expected from a high quality library. In
// particular, how report IDs are handled is not uniform on the 3
// platforms. The mac code uses a single buffer which assumes no
// other functions can cause the "run loop" to process HID callbacks.
// The linux version doesn't extract usage and usage page from the
// report descriptor and just hardcodes a signature for the Teensy
// USB debug example. Lacking from all platforms are functions to
// manage multiple devices and robust detection of device removal
// and attachment. There are probably lots of other issues... this
// code has really only been used in 2 projects. If you use it,
// please report bugs to paul@pjrc.com
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "rawhid.h"
#ifdef OPERATING_SYSTEM
#undef OPERATING_SYSTEM
#endif
/*************************************************************************/
/** **/
/** Linux **/
/** **/
/*************************************************************************/
#if defined(LINUX) || defined(__LINUX__) || #system(linux)
#define OPERATING_SYSTEM linux
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/hidraw.h>
struct rawhid_struct {
int fd;
int name;
int isok;
};
rawhid_t * rawhid_open_only1(int vid, int pid, int usage_page, int usage)
{
struct rawhid_struct *hid;
struct stat devstat;
struct hidraw_devinfo info;
struct hidraw_report_descriptor *desc;
char buf[512];
// TODO; inputs are ignored and hardcoded into this signature....
const unsigned char signature[]={0x06,0x31,0xFF,0x09,0x74};
int r, i, fd=-1, len, found=0;
//printf("Searching for device using hidraw....\n");
for (i=0; i<HIDRAW_MAX_DEVICES; i++) {
if (fd > 0) close(fd);
snprintf(buf, sizeof(buf), "/dev/hidraw%d", i);
r = stat(buf, &devstat);
if (r < 0) continue;
//printf("device: %s\n", buf);
fd = open(buf, O_RDWR);
if (fd < 0) continue;
//printf(" opened\n");
r = ioctl(fd, HIDIOCGRAWINFO, &info);
if (r < 0) continue;
//printf(" vid=%04X, pid=%04X\n", info.vendor & 0xFFFF, info.product & 0xFFFF);
r = ioctl(fd, HIDIOCGRDESCSIZE, &len);
if (r < 0 || len < 1) continue;
//printf(" len=%u\n", len);
desc = (struct hidraw_report_descriptor *)buf;
if (len > sizeof(buf)-sizeof(int)) len = sizeof(buf)-sizeof(int);
desc->size = len;
r = ioctl(fd, HIDIOCGRDESC, desc);
if (r < 0) continue;
if (len >= sizeof(signature) &&
memcmp(desc->value, signature, sizeof(signature)) == 0) {
//printf(" Match\n");
found = 1;
break;
}
}
if (!found) {
if (fd > 0) close(fd);
return NULL;
}
hid = (struct rawhid_struct *)malloc(sizeof(struct rawhid_struct));
if (!hid) {
close(fd);
return NULL;
}
hid->fd = fd;
return hid;
}
int rawhid_status(rawhid_t *hid)
{
// TODO: how to check if device is still online?
return -1;
}
int rawhid_read(rawhid_t *h, void *buf, int bufsize, int timeout_ms)
{
struct rawhid_struct *hid;
int num;
hid = (struct rawhid_struct *)h;
if (!hid || hid->fd < 0) return -1;
while (1) {
num = read(hid->fd, buf, bufsize);
if (num < 0) {
if (errno == EINTR || errno == EAGAIN) continue;
if (errno == EIO) {
return -1;
printf("I/O Error\n");
}
printf("read error, r=%d, errno=%d\n", num, errno);
return -1;
}
//printf("read %d bytes\n", num);
return num;
}
}
void rawhid_close(rawhid_t *h)
{
struct rawhid_struct *hid;
hid = (struct rawhid_struct *)h;
if (!hid || hid->fd < 0) return;
close(hid->fd);
hid->fd = -1;
}
#if 0
struct rawhid_list_struct {
int count;
struct rawhid_list_entry {
int name;
int desc_length;
const char *desc;
} dev[HIDRAW_MAX_DEVICES];
};
rawhid_list_t * rawhid_list_open(int vid, int pid, int usage_page, int usage)
{
struct rawhid_list_struct *list;
struct stat devstat;
struct hidraw_devinfo info;
struct hidraw_report_descriptor *desc;
char buf[512], *p;
const unsigned char signature[]={0x06,0x31,0xFF,0x09,0x74};
int r, i, fd=-1, len;
list = (struct rawhid_list_struct *)malloc(sizeof(struct rawhid_list_struct));
if (!list) return NULL;
list->count = 0;
printf("Searching for device using hidraw....\n");
for (i=0; i<HIDRAW_MAX_DEVICES; i++) {
if (fd > 0) close(fd);
snprintf(buf, sizeof(buf), "/dev/hidraw%d", i);
r = stat(buf, &devstat);
if (r < 0) continue;
printf("device: %s\n", buf);
fd = open(buf, O_RDWR);
if (fd < 0) continue;
printf(" opened\n");
r = ioctl(fd, HIDIOCGRAWINFO, &info);
if (r < 0) continue;
printf(" vid=%04X, pid=%04X\n", info.vendor & 0xFFFF, info.product & 0xFFFF);
r = ioctl(fd, HIDIOCGRDESCSIZE, &len);
if (r < 0 || len < 1) continue;
printf(" len=%u\n", len);
desc = (struct hidraw_report_descriptor *)buf;
if (len > sizeof(buf)-sizeof(int)) len = sizeof(buf)-sizeof(int);
desc->size = len;
r = ioctl(fd, HIDIOCGRDESC, desc);
if (r < 0) continue;
if (len < sizeof(signature)) continue;
// TODO: actual report parsing would be nice!
if (memcmp(desc->value, signature, sizeof(signature)) != 0) continue;
p = (char *)malloc(len);
if (!p) continue;
printf(" Match\n");
memcpy(p, desc->value, len);
list->dev[list->count].desc = p;
list->dev[list->count].desc_length = len;
list->dev[list->count].name = i;
list->count++;
}
if (fd > 0) close(fd);
return list;
}
int rawhid_list_count(rawhid_list_t *list)
{
if (!list) return 0;
return ((struct rawhid_list_struct *)list)->count;
}
void rawhid_list_close(rawhid_list_t *list)
{
if (list) free(list);
}
#endif
#endif // linux
/*************************************************************************/
/** **/
/** Mac OS X 10.5 **/
/** **/
/*************************************************************************/
#if (defined(DARWIN) || defined(__DARWIN__)) && !defined(OPERATING_SYSTEM)
#define OPERATING_SYSTEM darwin
#include <IOKit/IOKitLib.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDDevice.h>
#include <unistd.h>
// http://developer.apple.com/technotes/tn2007/tn2187.html
struct rawhid_struct {
IOHIDDeviceRef ref;
int disconnected;
uint8_t *buffer;
int buffer_used;
int buffer_report_id;
};
static void unplug_callback(void *hid, IOReturn ret, void *ref)
{
// This callback can only be called when the "run loop" (managed by macos)
// is run. If the GUI is running it when idle, this will get called
// automatically. If not, the run loop needs to be run explicitly
// before checking the result of this function.
//printf("HID/macos: unplugged callback!\n");
((struct rawhid_struct *)hid)->disconnected = 1;
}
static void input_callback(void *context, IOReturn result, void *sender,
IOHIDReportType type, uint32_t reportID, uint8_t *report,
CFIndex reportLength)
{
struct rawhid_struct *hid;
//printf("input callback\n");
if (!context) return;
hid = (struct rawhid_struct *)context;
hid->buffer_used = reportLength;
hid->buffer_report_id = reportID;
//printf("id = %d, reportLength = %d\n", reportID, (int)reportLength);
//if (hid->ref == sender) printf("ref matches :-)\n");
//if (report == hid->buffer) printf("buffer matches :)\n");
}
rawhid_t * rawhid_open_only1(int vid, int pid, int usage_page, int usage)
{
IOHIDManagerRef hid_manager;
CFMutableDictionaryRef dict;
IOReturn ret;
CFSetRef device_set;
IOHIDDeviceRef device_list[256];
uint8_t *buf;
struct rawhid_struct *hid;
int num_devices;
// get access to the HID Manager
hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) {
printf("HID/macos: unable to access HID manager");
return NULL;
}
// configure it to look for our type of device
dict = IOServiceMatching(kIOHIDDeviceKey);
if (dict == NULL) {
printf("HID/macos: unable to create iokit dictionary");
return NULL;
}
if (vid > 0) {
CFDictionarySetValue(dict, CFSTR(kIOHIDVendorIDKey),
CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vid));
}
if (pid > 0) {
CFDictionarySetValue(dict, CFSTR(kIOHIDProductIDKey),
CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid));
}
if (usage_page > 0) {
CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsagePageKey),
CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page));
}
if (usage > 0) {
CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsageKey),
CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage));
}
IOHIDManagerSetDeviceMatching(hid_manager, dict);
// now open the HID manager
ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
if (ret != kIOReturnSuccess) {
printf("HID/macos: Unable to open HID manager (IOHIDManagerOpen failed)");
return NULL;
}
// get a list of devices that match our requirements
device_set = IOHIDManagerCopyDevices(hid_manager);
if (device_set == NULL) {
//printf("HID/macos: no devices found\n");
return NULL;
}
num_devices = (int)CFSetGetCount(device_set);
//printf("number of devices found = %d\n", num_devices);
if (num_devices < 1) {
CFRelease(device_set);
printf("HID/macos: no devices found, even though HID manager returned a set\n");
return NULL;
}
if (num_devices > 256) {
CFRelease(device_set);
printf("HID/macos: too many devices, we get confused if more than 256!\n");
return NULL;
}
CFSetGetValues(device_set, (const void **)&device_list);
CFRelease(device_set);
// open the first device in the list
ret = IOHIDDeviceOpen(device_list[0], kIOHIDOptionsTypeNone);
if (ret != kIOReturnSuccess) {
printf("HID/macos: error opening device\n");
return NULL;
}
// return this device
hid = (struct rawhid_struct *)malloc(sizeof(struct rawhid_struct));
buf = (uint8_t *)malloc(0x1000);
if (hid == NULL || buf == NULL) {
IOHIDDeviceRegisterRemovalCallback(device_list[0], NULL, NULL);
IOHIDDeviceClose(device_list[0], kIOHIDOptionsTypeNone);
printf("HID/macos: Unable to allocate memory\n");
return NULL;
}
hid->ref = device_list[0];
hid->disconnected = 0;
hid->buffer = buf;
hid->buffer_used = 0;
// register a callback to receive input
IOHIDDeviceRegisterInputReportCallback(hid->ref, hid->buffer, 0x1000,
input_callback, hid);
// register a callback to find out when it's unplugged
IOHIDDeviceScheduleWithRunLoop(hid->ref, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDDeviceRegisterRemovalCallback(hid->ref, unplug_callback, hid);
return hid;
}
int rawhid_status(rawhid_t *hid)
{
if (!hid) return -1;
// if a GUI is causing the run loop run, this will likely mess it up. Just
// comment it out and if the callback still gets called without this, then
// there's no need to run the run loop here!
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ;
if (((struct rawhid_struct *)hid)->disconnected) {
//printf("HID/macos: status: disconnected\n");
return -1;
}
//printf("HID/macos: status: ok\n");
return 0;
}
void rawhid_close(rawhid_t *hid)
{
IOHIDDeviceRef ref;
if (!hid) return;
ref = ((struct rawhid_struct *)hid)->ref;
IOHIDDeviceRegisterRemovalCallback(ref, NULL, NULL);
IOHIDDeviceClose(ref, kIOHIDOptionsTypeNone);
free(hid);
}
int rawhid_read(rawhid_t *h, void *buf, int bufsize, int timeout_ms)
{
struct rawhid_struct *hid;
int r, len;
//printf("begin read\n");
hid = (struct rawhid_struct *)h;
if (!hid || hid->disconnected) return -1;
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) {
if (hid->buffer_used) {
len = hid->buffer_used;
if (len > bufsize) len = bufsize;
memcpy(buf, hid->buffer, len);
hid->buffer_used = 0;
return len;
}
if (hid->disconnected) {
return -1;
}
}
r = CFRunLoopRunInMode(kCFRunLoopDefaultMode, (double)timeout_ms / 1000.0, true);
if (r == kCFRunLoopRunTimedOut) {
//printf("read timeout\n");
return 0;
}
if (hid->buffer_used) {
len = hid->buffer_used;
if (len > bufsize) len = bufsize;
memcpy(buf, hid->buffer, len);
hid->buffer_used = 0;
return len;
}
if (hid->disconnected) return -1;
return 0;
//num = bufsize;
//ret = IOHIDDeviceGetReport(ref, kIOHIDReportTypeInput, 0, buf, &num);
//if (!ret) return -1;
//return num;
}
int rawhid_write(rawhid_t *hid, const void *buf, int len, int timeout_ms)
{
IOReturn ret;
if (((struct rawhid_struct *)hid)->disconnected) return -1;
ret = IOHIDDeviceSetReport(((struct rawhid_struct *)hid)->ref,
kIOHIDReportTypeOutput, 0, buf, len);
if (ret != kIOReturnSuccess) return -1;
return 0;
}
#endif // Darwin - Mac OS X
/*************************************************************************/
/** **/
/** Windows 2000/XP/Vista **/
/** **/
/*************************************************************************/
#if (defined(WIN32) || defined(WINDOWS) || defined(__WINDOWS__)) && !defined(OPERATING_SYSTEM)
#define OPERATING_SYSTEM windows
#include <windows.h>
#include <setupapi.h>
#include <ddk/hidsdi.h>
#include <ddk/hidclass.h>
// http://msdn.microsoft.com/en-us/library/ms790932.aspx
struct rawhid_struct {
HANDLE handle;
};
rawhid_t * rawhid_open_only1(int vid, int pid, int usage_page, int usage)
{
GUID guid;
HDEVINFO info;
DWORD index=0, required_size;
SP_DEVICE_INTERFACE_DATA iface;
SP_DEVICE_INTERFACE_DETAIL_DATA *details;
HIDD_ATTRIBUTES attrib;
PHIDP_PREPARSED_DATA hid_data;
HIDP_CAPS capabilities;
struct rawhid_struct *hid;
HANDLE h;
BOOL ret;
HidD_GetHidGuid(&guid);
info = SetupDiGetClassDevs(&guid, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (info == INVALID_HANDLE_VALUE) {
printf("HID/win32: SetupDiGetClassDevs failed");
return NULL;
}
for (index=0; ;index++) {
iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
if (!ret) {
// end of list
SetupDiDestroyDeviceInfoList(info);
return NULL;
}
SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &required_size, NULL);
details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(required_size);
if (details == NULL) continue;
memset(details, 0, required_size);
details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
required_size, NULL, NULL);
if (!ret) {
free(details);
continue;
}
h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
free(details);
if (h == INVALID_HANDLE_VALUE) continue;
attrib.Size = sizeof(HIDD_ATTRIBUTES);
ret = HidD_GetAttributes(h, &attrib);
if (!ret) {
CloseHandle(h);
continue;
}
//printf("HID/win32: USB Device:\n");
//printf("HID/win32: vid = 0x%04X\n", (int)(attrib.VendorID));
//printf("HID/win32: pid = 0x%04X\n", (int)(attrib.ProductID));
if (vid > 0 && vid != (int)(attrib.VendorID)) {
CloseHandle(h);
continue;
}
if (pid > 0 && pid != (int)(attrib.ProductID)) {
CloseHandle(h);
continue;
}
if (!HidD_GetPreparsedData(h, &hid_data)) {
printf("HID/win32: HidD_GetPreparsedData failed\n");
CloseHandle(h);
continue;
}
if (!HidP_GetCaps(hid_data, &capabilities)) {
printf("HID/win32: HidP_GetCaps failed\n");
HidD_FreePreparsedData(hid_data);
CloseHandle(h);
continue;
}
//printf("HID/win32: usage_page = 0x%04X\n", (int)(capabilities.UsagePage));
//printf("HID/win32: usage = 0x%04X\n", (int)(capabilities.Usage));
if (usage_page > 0 && usage_page != (int)(capabilities.UsagePage)) {
HidD_FreePreparsedData(hid_data);
CloseHandle(h);
continue;
}
if (usage > 0 && usage != (int)(capabilities.Usage)) {
HidD_FreePreparsedData(hid_data);
CloseHandle(h);
continue;
}
HidD_FreePreparsedData(hid_data);
hid = (struct rawhid_struct *)malloc(sizeof(struct rawhid_struct));
if (!hid) {
CloseHandle(h);
printf("HID/win32: Unable to get %d bytes", sizeof(struct rawhid_struct));
continue;
}
hid->handle = h;
return hid;
}
}
int rawhid_status(rawhid_t *hid)
{
PHIDP_PREPARSED_DATA hid_data;
if (!hid) return -1;
if (!HidD_GetPreparsedData(((struct rawhid_struct *)hid)->handle, &hid_data)) {
printf("HID/win32: HidD_GetPreparsedData failed, device assumed disconnected\n");
return -1;
}
printf("HID/win32: HidD_GetPreparsedData ok, device still online :-)\n");
HidD_FreePreparsedData(hid_data);
return 0;
}
void rawhid_close(rawhid_t *hid)
{
if (!hid) return;
CloseHandle(((struct rawhid_struct *)hid)->handle);
free(hid);
}
int rawhid_read(rawhid_t *h, void *buf, int bufsize, int timeout_ms)
{
DWORD num=0, result;
BOOL ret;
OVERLAPPED ov;
struct rawhid_struct *hid;
int r;
hid = (struct rawhid_struct *)h;
if (!hid) return -1;
memset(&ov, 0, sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ov.hEvent == NULL) return -1;
ret = ReadFile(hid->handle, buf, bufsize, &num, &ov);
if (ret) {
//printf("HID/win32: read success (immediate)\n");
r = num;
} else {
if (GetLastError() == ERROR_IO_PENDING) {
result = WaitForSingleObject(ov.hEvent, timeout_ms);
if (result == WAIT_OBJECT_0) {
if (GetOverlappedResult(hid->handle, &ov, &num, FALSE)) {
//printf("HID/win32: read success (delayed)\n");
r = num;
} else {
//printf("HID/win32: read failure (delayed)\n");
r = -1;
}
} else {
//printf("HID/win32: read timeout, %lx\n", result);
CancelIo(hid->handle);
r = 0;
}
} else {
//printf("HID/win32: read error (immediate)\n");
r = -1;
}
}
CloseHandle(ov.hEvent);
return r;
}
int rawhid_write(rawhid_t *h, const void *buf, int len, int timeout_ms)
{
DWORD num=0;
BOOL ret;
OVERLAPPED ov;
struct rawhid_struct *hid;
int r;
hid = (struct rawhid_struct *)h;
if (!hid) return -1;
memset(&ov, 0, sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ov.hEvent == NULL) return -1;
// first byte is report ID, must be zero if report IDs not used
ret = WriteFile(hid->handle, buf, len, &num, &ov);
if (ret) {
if (num == len) {
//printf("HID/win32: write success (immediate)\n");
r = 0;
} else {
//printf("HID/win32: partial write (immediate)\n");
r = -1;
}
} else {
if (GetLastError() == ERROR_IO_PENDING) {
if (GetOverlappedResult(hid->handle, &ov, &num, TRUE)) {
if (num == len) {
//printf("HID/win32: write success (delayed)\n");
r = 0;
} else {
//printf("HID/win32: partial write (delayed)\n");
r = -1;
}
} else {
//printf("HID/win32: write error (delayed)\n");
r = -1;
}
} else {
//printf("HID/win32: write error (immediate)\n");
r = -1;
}
}
CloseHandle(ov.hEvent);
return r;
}
#endif // windows
#ifndef OPERATING_SYSTEM
#error Unknown operating system
#endif

23
hid_listen/rawhid.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef rawhid_included_h__
#define rawhid_included_h__
// Raw HID, Basic API
typedef void rawhid_t;
rawhid_t * rawhid_open_only1(int vid, int pid, int usage_page, int usage);
int rawhid_status(rawhid_t *hid);
int rawhid_read(rawhid_t *h, void *buf, int bufsize, int timeout_ms);
int rawhid_write(rawhid_t *hid, const void *buf, int len, int timeout_ms);
void rawhid_close(rawhid_t *h);
// Raw HID, Multiple Device API
typedef void rawhid_list_t;
rawhid_list_t * rawhid_list_open(int vid, int pid, int usage_page, int usage);
int rawhid_list_count(rawhid_list_t *list);
void rawhid_list_close(rawhid_list_t *list);
int rawhid_list_indexof(rawhid_list_t *list, rawhid_t *hid);
void rawhid_list_remove(rawhid_list_t *list, rawhid_t *hid);
rawhid_t * rawhid_open(rawhid_list_t *list, int index);
#endif