From e4294c52d38e682efbce61cc333b0ae7f1cdf219 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 1 Aug 2006 03:02:21 +0000 Subject: separated usbhid into its own folder since it had dependencies that don't work on all platforms svn path=/trunk/externals/hcs/; revision=5448 --- usbhid-help.pd | 139 --------- usbhid.c | 782 -------------------------------------------------- usbhid.libs | 1 - usbhid/usbhid-help.pd | 139 +++++++++ usbhid/usbhid.c | 782 ++++++++++++++++++++++++++++++++++++++++++++++++++ usbhid/usbhid.libs | 1 + 6 files changed, 922 insertions(+), 922 deletions(-) delete mode 100644 usbhid-help.pd delete mode 100644 usbhid.c delete mode 100644 usbhid.libs create mode 100644 usbhid/usbhid-help.pd create mode 100644 usbhid/usbhid.c create mode 100644 usbhid/usbhid.libs diff --git a/usbhid-help.pd b/usbhid-help.pd deleted file mode 100644 index 08127b2..0000000 --- a/usbhid-help.pd +++ /dev/null @@ -1,139 +0,0 @@ -#N canvas 254 84 629 549 10; -#X obj 132 376 usbhid; -#X msg 184 91 close; -#X msg 184 117 reset; -#X text 240 307 GARBAGE FOR TESTING; -#X msg 197 155 print; -#X text 317 72 Gravis/Destroyer Tiltpad; -#X text 311 43 Microsoft 5-button Mouse; -#N canvas 0 22 462 312 buttons 0; -#X obj 99 36 inlet; -#X obj 63 108 & 1; -#X obj 63 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 -; -#X obj 93 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 2 -; -#X obj 123 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -4; -#X obj 153 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -8; -#X obj 183 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -16; -#X obj 223 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -32; -#X obj 263 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 303 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -128; -#X obj 93 108 & 2; -#X obj 123 108 & 4; -#X obj 153 108 & 8; -#X obj 183 108 & 16; -#X obj 223 108 & 32; -#X obj 263 108 & 64; -#X obj 303 108 & 128; -#X connect 0 0 1 0; -#X connect 0 0 10 0; -#X connect 0 0 11 0; -#X connect 0 0 12 0; -#X connect 0 0 13 0; -#X connect 0 0 14 0; -#X connect 0 0 15 0; -#X connect 0 0 16 0; -#X connect 1 0 2 0; -#X connect 10 0 3 0; -#X connect 11 0 4 0; -#X connect 12 0 5 0; -#X connect 13 0 6 0; -#X connect 14 0 7 0; -#X connect 15 0 8 0; -#X connect 16 0 9 0; -#X restore 65 515 pd buttons test; -#X obj 127 462 unpack float float float float; -#X obj 44 83 metro 400; -#X obj 46 57 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 -; -#X floatatom 186 499 5 0 0 0 - - -; -#X floatatom 256 500 5 0 0 0 - - -; -#X floatatom 336 495 5 0 0 0 - - -; -#X msg 171 43 open 0x045e 0x0039; -#X msg 157 13 open vendorId productId; -#X msg 176 71 open 0x047D 0x4008; -#X floatatom 125 496 5 0 0 0 - - -; -#X msg 239 273 debug \$1; -#X obj 239 251 hradio 15 1 0 10 empty empty empty 0 -6 0 8 -262144 --1 -1 0; -#X obj 27 441 print data; -#N canvas 458 151 454 485 parsing 0; -#X obj 77 6 inlet; -#X obj 80 101 route float symbol; -#X obj 80 190 mapping/tolist; -#X obj 139 137 trigger symbol bang; -#X msg 22 139 bang; -#X obj 81 226 list trim; -#X obj 241 312 print; -#X obj 80 272 route path; -#X obj 34 328 print path-------------; -#X obj 78 31 list-abs/list-drip; -#X obj 198 51 trigger bang bang; -#X obj 247 89 print end---------; -#X connect 0 0 9 0; -#X connect 1 0 2 0; -#X connect 1 1 3 0; -#X connect 2 0 5 0; -#X connect 3 0 2 0; -#X connect 3 1 2 1; -#X connect 4 0 2 0; -#X connect 5 0 7 0; -#X connect 7 0 8 0; -#X connect 7 1 6 0; -#X connect 9 0 1 0; -#X connect 9 1 10 0; -#X connect 10 0 2 1; -#X connect 10 1 11 0; -#X restore 226 418 pd parsing; -#X text 8 122 how many bytes to read; -#X msg 194 136 refresh; -#X text 259 137 reinit and refresh device list; -#X text 233 117 resets device (don't really know what that does tho) -; -#X obj 171 419 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 -1; -#X obj 171 397 route open device; -#X msg 44 104 get 4; -#X msg 82 137 get 2; -#X msg 212 179 descriptor; -#X text 291 179 get descriptor; -#X msg 219 213 descriptor 1 30 1 31 1 38; -#X text 398 212 [descriptor page# usage# ...(; -#X text 218 197 for writing to the device:; -#X msg 25 208 set 2; -#X msg 237 323 close \, open 0x045e 0x0039 \, descriptor; -#X text 183 382 <- status outlet; -#X text 21 383 data outlet ->; -#X connect 0 0 8 0; -#X connect 0 0 20 0; -#X connect 0 1 27 0; -#X connect 1 0 0 0; -#X connect 2 0 0 0; -#X connect 4 0 0 0; -#X connect 8 0 7 0; -#X connect 8 0 17 0; -#X connect 8 1 11 0; -#X connect 8 2 12 0; -#X connect 8 3 13 0; -#X connect 9 0 28 0; -#X connect 10 0 9 0; -#X connect 14 0 0 0; -#X connect 16 0 0 0; -#X connect 18 0 0 0; -#X connect 19 0 18 0; -#X connect 23 0 0 0; -#X connect 27 0 26 0; -#X connect 27 1 21 0; -#X connect 28 0 0 0; -#X connect 29 0 0 0; -#X connect 30 0 0 0; -#X connect 32 0 0 0; -#X connect 35 0 0 0; -#X connect 36 0 0 0; diff --git a/usbhid.c b/usbhid.c deleted file mode 100644 index 5fc069f..0000000 --- a/usbhid.c +++ /dev/null @@ -1,782 +0,0 @@ -/* --------------------------------------------------------------------------*/ -/* */ -/* Pd interface to the USB HID API using libhid, which is built on libusb */ -/* Written by Hans-Christoph Steiner */ -/* */ -/* Copyright (c) 2004 Hans-Christoph Steiner */ -/* */ -/* 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 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* --------------------------------------------------------------------------*/ - -/* libhid hasn't been ported to Win32 yet */ -#ifndef _WIN32 - -#include -#include -#include -#include -#include -#include "m_pd.h" - -/* - * TODO: rename read, get, set messages so they make sense - * TODO: make size output work well - */ - -/* - * BUG: for some reason it skips one of the button bits - */ - - -/*------------------------------------------------------------------------------ - * INCLUDE KLUDGE - */ - -/* NOTE: included from libusb/usbi.h. UGLY, i know, but so is libusb! - * this struct doesn't seem to be defined in usb.h, only prototyped - */ -struct usb_dev_handle { - int fd; - struct usb_bus *bus; - struct usb_device *device; - int config; - int interface; - int altsetting; - void *impl_info; -}; - - -/*------------------------------------------------------------------------------ - * GLOBAL VARIABLES - */ - -/* count the number of instances of this object so that certain free() - * functions can be called only after the final instance is detroyed. */ -t_int usbhid_instance_count; - -#define HID_ID_MAX 32 -char *hid_id[HID_ID_MAX]; /* FIXME: 32 devices MAX */ -t_int hid_id_count; - -/* this array is for keeping track of whether each device has been read in - * each cycle */ -char usbhid_device_read_status[HID_ID_MAX]; - -/*------------------------------------------------------------------------------ - * CLASS DEF - */ - -typedef struct _usbhid -{ - t_object x_obj; -/* usbhid types */ - HIDInterface *x_hidinterface; - hid_return x_hid_return; -/* internal state */ - unsigned short vendor_id; // idVendor for current device - unsigned short product_id; // idProduct for current device - unsigned short debug_level; // control debug messages to the console - t_int x_device_number; - t_int x_read_element_count; - t_int *x_read_elements; - t_int x_write_element_count; - t_int *x_write_elements; - t_int report_size; // size in bytes of the HID report -/* output */ - t_atom *output; // holder for a list of atoms to be outputted - t_int output_count; // number of atoms in in x->output - t_outlet *x_data_outlet; - t_outlet *x_status_outlet; -} t_usbhid; - - -/*------------------------------------------------------------------------------ - * LOCAL DEFINES - */ - -#define USBHID_MAJOR_VERSION 0 -#define USBHID_MINOR_VERSION 0 - -static t_class *usbhid_class; - -/* for USB strings */ -#define STRING_BUFFER_LENGTH 256 - -#define SEND_PACKET_LENGTH 1 -#define RECEIVE_PACKET_LENGTH 6 -#define PATH_LENGTH 3 - - -/*------------------------------------------------------------------------------ - * SUPPORT FUNCTIONS - */ - -/* add one new atom to the list to be outputted */ -static void add_atom_to_output(t_usbhid *x, t_atom *new_atom) -{ - t_atom *new_atom_list; - - new_atom_list = (t_atom *)getbytes((x->output_count + 1) * sizeof(t_atom)); - memcpy(new_atom_list, x->output, x->output_count * sizeof(t_atom)); - freebytes(x->output, x->output_count * sizeof(t_atom)); - x->output = new_atom_list; - memcpy(x->output + x->output_count, new_atom, sizeof(t_atom)); - ++(x->output_count); -} - -static void add_symbol_to_output(t_usbhid *x, t_symbol *s) -{ - t_atom *temp_atom = getbytes(sizeof(t_atom)); - SETSYMBOL(temp_atom, s); - add_atom_to_output(x,temp_atom); - freebytes(temp_atom,sizeof(t_atom)); -} - -static void add_float_to_output(t_usbhid *x, t_float f) -{ - t_atom *temp_atom = getbytes(sizeof(t_atom)); - SETFLOAT(temp_atom, f); - add_atom_to_output(x,temp_atom); - freebytes(temp_atom,sizeof(t_atom)); -} - -static void reset_output(t_usbhid *x) -{ - if(x->output) - { - freebytes(x->output, x->output_count * sizeof(t_atom)); - x->output = NULL; - x->output_count = 0; - } -} - - -static t_int init_libhid(t_usbhid *x) -{ - if (! hid_is_initialised() ) - { - x->x_hid_return = hid_init(); - if(x->x_hid_return != HID_RET_SUCCESS) - { - error("[usbhid] hid_init failed with return code %d\n", - x->x_hid_return); - } - } - return(x->x_hid_return); -} - - -/* - * This function is used in a HIDInterfaceMatcher to iterate thru all of the - * HID devices on the USB bus - */ -static bool device_iterator (struct usb_dev_handle const* usbdev, void* custom, - unsigned int length) -{ - bool ret = false; - t_int i; - char current_dev_path[10]; - - /* only here to prevent the unused warning */ - /* TODO remove */ - length = *((unsigned long*)custom); - - /* Obtain the device's full path */ - sprintf(current_dev_path, "%s/%s", usbdev->bus->dirname, usbdev->device->filename); - - /* Check if we already saw this dev */ - for ( i = 0 ; ( hid_id[i] != NULL ) ; i++ ) - { - if (!strcmp(hid_id[i], current_dev_path ) ) - break; - } - - /* Append device to the list if needed */ - if (hid_id[i] == NULL) - { - hid_id[i] = (char *) malloc(strlen(usbdev->device->filename) + strlen(usbdev->bus->dirname) ); - sprintf(hid_id[i], "%s/%s", usbdev->bus->dirname, usbdev->device->filename); - } - else /* device already seen */ - { - return false; - } - - /* Filter non HID device */ - if ( (usbdev->device->descriptor.bDeviceClass == 0) /* Class defined at interface level */ - && usbdev->device->config - && usbdev->device->config->interface->altsetting->bInterfaceClass == USB_CLASS_HID) - { - - post("bus %s device %s: %d %d", - usbdev->bus->dirname, - usbdev->device->filename, - usbdev->device->descriptor.idVendor, - usbdev->device->descriptor.idProduct); - ret = true; - } - - else - { - ret = false; - } - - - return ret; -} - -/* -------------------------------------------------------------------------- */ -/* This function is used in a HIDInterfaceMatcher in order to match devices by - * serial number. - */ -/* static bool match_serial_number(struct usb_dev_handle* usbdev, void* custom, unsigned int length) */ -/* { */ -/* bool ret; */ -/* char* buffer = (char*)malloc(length); */ -/* usb_get_string_simple(usbdev, usb_device(usbdev)->descriptor.iSerialNumber, */ -/* buffer, length); */ -/* ret = strncmp(buffer, (char*)custom, length) == 0; */ -/* free(buffer); */ -/* return ret; */ -/* } */ - - -/* -------------------------------------------------------------------------- */ -/* static bool get_device_by_number(struct usb_dev_handle* usbdev, */ -/* void* custom, */ -/* unsigned int length) */ -/* { */ -/* bool ret; */ - - -/* return ret; */ -/* } */ - - -/* -------------------------------------------------------------------------- */ -static t_int* make_hid_path(t_int element_count, t_int argc, t_atom *argv) -{ - t_int i; - t_int *return_array = NULL; - - post("element_count %d",element_count); - return_array = (t_int *) getbytes(sizeof(t_int) * element_count); - for(i=0; i < element_count; ++i) - { -/* - * A usbhid path component is 32 bits, the high 16 bits identify the usage page, - * and the low 16 bits the item number. - */ - return_array[i] = - (atom_getintarg(i*2,argc,argv) << 16) + atom_getintarg(i*2+1,argc,argv); -/* TODO: print error if a symbol is found in the data list */ - } - return return_array; -} - - -static t_int get_device_string(HIDInterface *hidif, char *device_string) -{ - int length; - t_int ret = 0; - char buffer[STRING_BUFFER_LENGTH]; - - if ( !hid_is_opened(hidif) ) - return(0); - - if (hidif->device->descriptor.iManufacturer) { - length = usb_get_string_simple(hidif->dev_handle, - hidif->device->descriptor.iManufacturer, - buffer, - STRING_BUFFER_LENGTH); - if (length > 0) - { - strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string)); - strncat(device_string, " ",1); - ret = 1; - } - else - { - post("(unable to fetch manufacturer string)"); - } - } - - if (hidif->device->descriptor.iProduct) { - length = usb_get_string_simple(hidif->dev_handle, - hidif->device->descriptor.iProduct, - buffer, - STRING_BUFFER_LENGTH); - if (length > 0) - { - strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string)); - strncat(device_string, " ",1); - ret = 1; - } - else - { - post("(unable to fetch product string)"); - } - } - - if (hidif->device->descriptor.iSerialNumber) { - length = usb_get_string_simple(hidif->dev_handle, - hidif->device->descriptor.iSerialNumber, - buffer, - STRING_BUFFER_LENGTH); - if (length > 0) - strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string)); - else - post("(unable to fetch product string)"); - } - - return ret; -} - - -/*------------------------------------------------------------------------------ - * IMPLEMENTATION - */ - - -/* -------------------------------------------------------------------------- */ -static void usbhid_close(t_usbhid *x) -{ - if(x->debug_level) post("usbhid_close"); - t_int ret; - char string_buffer[STRING_BUFFER_LENGTH]; - - if ( hid_is_opened(x->x_hidinterface) ) - { - ret = get_device_string(x->x_hidinterface,string_buffer); - x->x_hid_return = hid_close(x->x_hidinterface); - if (x->x_hid_return == HID_RET_SUCCESS) - { - if (ret) - post("[usbhid]: closed %s",string_buffer); - else - post("[usbhid]: closed device"); - reset_output(x); - add_float_to_output(x,0); - outlet_anything(x->x_status_outlet, gensym("open"), - x->output_count, x->output); - } - else - { - error("[usbhid] could not close %d, error #%d",x->x_device_number,x->x_hid_return); - } - } -} - - -/* -------------------------------------------------------------------------- */ -static void usbhid_open(t_usbhid *x, t_symbol *vendor_id_hex, t_symbol *product_id_hex) -{ - if(x->debug_level) post("usbhid_open"); - char string_buffer[STRING_BUFFER_LENGTH]; - - if( init_libhid(x) != HID_RET_SUCCESS ) return; - -/* convert hex symbols to ints */ - x->vendor_id = (unsigned short) strtol(vendor_id_hex->s_name, NULL, 16); - x->product_id = (unsigned short) strtol(product_id_hex->s_name, NULL, 16); - if( hid_is_opened(x->x_hidinterface) ) - { - if( (x->vendor_id == x->x_hidinterface->device->descriptor.idVendor) && - (x->product_id == x->x_hidinterface->device->descriptor.idProduct)) - { - post("[usbhid] device already opened"); - return; - } - else - { - usbhid_close(x); - } - } - - if( !hid_is_opened(x->x_hidinterface) ) - { - HIDInterfaceMatcher matcher = { x->vendor_id, - x->product_id, - NULL, - NULL, - 0 }; - x->x_hid_return = hid_force_open(x->x_hidinterface, 0, &matcher, 3); - if (x->x_hid_return == HID_RET_SUCCESS) - { - if (get_device_string(x->x_hidinterface,string_buffer)) - post("[usbhid]: opened %s",string_buffer); - reset_output(x); - add_float_to_output(x,1); - outlet_anything(x->x_status_outlet, gensym("open"), - x->output_count, x->output); - } - else - { - error("[usbhid] hid_force_open failed with return code %d\n", - x->x_hid_return); - } - } -} - - -/* -------------------------------------------------------------------------- */ -static void usbhid_set(t_usbhid *x, t_float length_arg) -{ - if(x->debug_level) post("usbhid_set"); - int packet_bytes = (int)length_arg; - char packet[packet_bytes]; - - if ( !hid_is_opened(x->x_hidinterface) ) - { - error("[usbhid] device not open, can't set data"); - return; - } - x->x_hid_return = hid_set_output_report(x->x_hidinterface, - x->x_write_elements, - x->x_write_element_count, - packet, - length_arg); - if (x->x_hid_return != HID_RET_SUCCESS) - { - error("[usbhid] hid_get_input_report failed with return code %d\n", - x->x_hid_return); - reset_output(x); - add_float_to_output(x, x->x_hid_return); - outlet_anything(x->x_status_outlet, gensym("setError"), - x->output_count, x->output); - } -} - -/* -------------------------------------------------------------------------- */ -static void usbhid_get(t_usbhid *x, t_float length_arg) -{ - if(x->debug_level) post("usbhid_get"); - int i; - int packet_bytes = (int)length_arg; - char packet[packet_bytes]; - - if ( !hid_is_opened(x->x_hidinterface) ) - { - error("[usbhid] device not open, can't get data"); - return; - } - x->x_hid_return = hid_get_input_report(x->x_hidinterface, - NULL, - x->x_read_element_count, - packet, - length_arg); - if (x->x_hid_return != HID_RET_SUCCESS) - { - error("[usbhid] hid_get_input_report failed with return code %d\n", - x->x_hid_return); - reset_output(x); - add_float_to_output(x, x->x_hid_return); - outlet_anything(x->x_status_outlet, gensym("getError"), - x->output_count, x->output); - } - - reset_output(x); - for(i=0; ix_data_outlet, &s_list, x->output_count, x->output); - post("x->x_read_elements %d",x->x_read_elements); -} - - -/* -------------------------------------------------------------------------- */ -/* reinit libhid to get update the list of attached devices */ -static void usbhid_refresh(t_usbhid *x) -{ - x->x_hid_return = hid_cleanup(); - if (x->x_hid_return != HID_RET_SUCCESS) - error("[usbhid] hid_cleanup failed with return code %d\n", - x->x_hid_return); - if( init_libhid(x) != HID_RET_SUCCESS ) return; -} - - -/* -------------------------------------------------------------------------- */ -/* set the HID packet for which elements to read */ -static void usbhid_set_read(t_usbhid *x, int argc, t_atom *argv) -{ - if(x->debug_level) post("usbhid_set_read"); - t_int i; - - x->x_read_element_count = argc / 2; - x->x_read_elements = make_hid_path(x->x_read_element_count, argc, argv); - post("x_read_element_count %d",x->x_read_element_count); - for(i=0;ix_read_element_count;++i) - post("x_read_elements %d: %d",i,x->x_read_elements[i]); -} - - -/* -------------------------------------------------------------------------- */ -/* convert a list to a HID packet and set it */ -/* set the HID packet for which elements to write */ -static void usbhid_set_descriptor(t_usbhid *x, int argc, t_atom *argv) -{ - if(x->debug_level) post("usbhid_descriptor"); -/* int const PATH_IN[PATH_LENGTH] = { 0xffa00001, 0xffa00002, 0xffa10003 }; */ -// int const PATH_OUT[3] = { 0x00010002, 0x00010001, 0x00010030 }; - t_int i; - - x->x_write_element_count = argc / 2; - x->x_write_elements = make_hid_path(x->x_write_element_count, argc, argv); - post("x_write_element_count %d",x->x_write_element_count); - for(i=0;ix_write_element_count;++i) - post("x_write_elements %d: %d",i,x->x_write_elements[i]); -} - - - -/* -------------------------------------------------------------------------- */ -static void usbhid_get_descriptor(t_usbhid *x) -{ - if(x->debug_level) post("usbhid_get"); - unsigned int i = 0; - t_int input_size = 0; - t_int output_size = 0; - t_int feature_size = 0; - - if (!hid_is_opened(x->x_hidinterface)) { - error("[usbget] cannot dump tree of unopened HIDinterface."); - } - else - { - post("[usbhid] parse tree of HIDInterface %s:\n", x->x_hidinterface->id); - reset_output(x); - while (HIDParse(x->x_hidinterface->hid_parser, x->x_hidinterface->hid_data)) { - add_symbol_to_output(x, gensym("path")); - switch(x->x_hidinterface->hid_data->Type) - { - case 0x80: - add_symbol_to_output(x, gensym("input")); - input_size = input_size + x->x_hidinterface->hid_data->Size; - break; - case 0x90: - add_symbol_to_output(x, gensym("output")); - output_size = output_size + x->x_hidinterface->hid_data->Size; - break; - case 0xb0: - add_symbol_to_output(x, gensym("feature")); - feature_size = feature_size + x->x_hidinterface->hid_data->Size; - break; - default: add_symbol_to_output(x, gensym("UNKNOWN_TYPE")); - } - add_float_to_output(x, x->x_hidinterface->hid_data->Size); - add_float_to_output(x, x->x_hidinterface->hid_data->Offset); - for (i = 0; i < x->x_hidinterface->hid_data->Path.Size; ++i) { - add_symbol_to_output(x, gensym("usage")); - add_float_to_output(x, x->x_hidinterface->hid_data->Path.Node[i].UPage); - add_float_to_output(x, x->x_hidinterface->hid_data->Path.Node[i].Usage); - post("page: 0x%04x\t%d\t\tusage: 0x%04x\t%d", - x->x_hidinterface->hid_data->Path.Node[i].UPage, - x->x_hidinterface->hid_data->Path.Node[i].UPage, - x->x_hidinterface->hid_data->Path.Node[i].Usage, - x->x_hidinterface->hid_data->Path.Node[i].Usage); - } - post("type: 0x%02x\n", x->x_hidinterface->hid_data->Type); - add_symbol_to_output(x, gensym("logical")); - add_float_to_output(x, x->x_hidinterface->hid_data->LogMin); - add_float_to_output(x, x->x_hidinterface->hid_data->LogMax); - } - add_symbol_to_output(x, gensym("totalSize")); - add_float_to_output(x, input_size); - add_float_to_output(x, output_size); - add_float_to_output(x, feature_size); - outlet_anything(x->x_status_outlet, gensym("device"), - x->output_count, x->output); - } -} - -/* -------------------------------------------------------------------------- */ -static void usbhid_descriptor(t_usbhid *x, t_symbol *s, int argc, t_atom *argv) -{ - if(s == gensym("descriptor")) // get rid of unused s warning - { - if(argc) - usbhid_set_descriptor(x,argc,argv); - else - usbhid_get_descriptor(x); - } -} - -/* -------------------------------------------------------------------------- */ -static void usbhid_print(t_usbhid *x) -{ - if(x->debug_level) post("usbhid_print"); - t_int i; - char string_buffer[STRING_BUFFER_LENGTH]; -/* t_atom event_data[3]; */ - - for ( i = 0 ; ( hid_id[i] != NULL ) ; i++ ) - { - if( hid_id[i] != NULL ) - post("hid_id[%d]: %s",i,hid_id[i]); - } - if(get_device_string(x->x_hidinterface,string_buffer)) - post("%s is currently open",string_buffer); - - x->x_hid_return = hid_dump_tree(stdout, x->x_hidinterface); - if (x->x_hid_return != HID_RET_SUCCESS) { - fprintf(stderr, "hid_dump_tree failed with return code %d\n", x->x_hid_return); - return; - } - -/* SETSYMBOL(event_data, gensym(type)); /\* type *\/ */ -/* SETSYMBOL(event_data + 1, gensym(code)); /\* code *\/ */ -/* SETSYMBOL(event_data + 2, value); /\* value *\/ */ -// outlet_list(x->x_status_outlet, &s_list, -} - - -/* -------------------------------------------------------------------------- */ -static void usbhid_reset(t_usbhid *x) -{ - if(x->debug_level) post("usbhid_reset"); - - hid_reset_HIDInterface(x->x_hidinterface); -} - - -/* -------------------------------------------------------------------------- */ -static void usbhid_debug(t_usbhid *x, t_float f) -{ - x->debug_level = f; - - switch(x->debug_level) - { - case 0: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_NONE); break; - case 1: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_ERRORS); break; - case 2: hid_set_usb_debug(0); - hid_set_debug(HID_DEBUG_ERRORS | HID_DEBUG_WARNINGS); break; - case 3: hid_set_usb_debug(0); - hid_set_debug(HID_DEBUG_ERRORS | HID_DEBUG_WARNINGS | HID_DEBUG_NOTICES); break; - case 4: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_NOTRACES); break; - case 5: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_ALL); break; - default: - hid_set_usb_debug(x->debug_level - 5); hid_set_debug(HID_DEBUG_ALL); break; - } -} - - -/* -------------------------------------------------------------------------- */ -static void usbhid_free(t_usbhid* x) -{ - if(x->debug_level) post("usbhid_free"); - - usbhid_close(x); - - freebytes(x->x_read_elements,sizeof(t_int) * x->x_read_element_count); - freebytes(x->x_write_elements,sizeof(t_int) * x->x_write_element_count); - - if(x->debug_level) - post("[usbhid] freeing instance %d",usbhid_instance_count); - hid_delete_HIDInterface(&(x->x_hidinterface)); - if(usbhid_instance_count <= 1) - { - post("[usbhid] freeing last instance"); - x->x_hid_return = hid_cleanup(); - if (x->x_hid_return != HID_RET_SUCCESS) - error("[usbhid] hid_cleanup failed with return code %d\n", - x->x_hid_return); - } - - usbhid_instance_count--; -} - - - -/* -------------------------------------------------------------------------- */ -static void *usbhid_new(t_float f) -{ - t_int i; - HIDInterfaceMatcher matcher; - t_usbhid *x = (t_usbhid *)pd_new(usbhid_class); - - if(x->debug_level) post("usbhid_new"); - -/* only display the version when the first instance is loaded */ - if(!usbhid_instance_count) - post("[usbhid] %d.%d, written by Hans-Christoph Steiner ", - USBHID_MAJOR_VERSION, USBHID_MINOR_VERSION); - - /* create anything outlet used for HID data */ - x->x_data_outlet = outlet_new(&x->x_obj, 0); - x->x_status_outlet = outlet_new(&x->x_obj, 0); - - /* turn off the flood of libhid debug messages by default */ - hid_set_debug(HID_DEBUG_NONE); - hid_set_debug_stream(stdout); - hid_set_usb_debug(0); - - /* data init */ - x->output = NULL; - x->output_count = 0; - for (i = 0 ; i < HID_ID_MAX ; i++) - hid_id[i] = NULL; - - x->x_hidinterface = hid_new_HIDInterface(); - matcher.vendor_id = HID_ID_MATCH_ANY; - matcher.product_id = HID_ID_MATCH_ANY; - matcher.matcher_fn = device_iterator; - - x->x_device_number = f; - -/* Open the device and save settings. If there is an error, return the object - * anyway, so that the inlets and outlets are created, thus not breaking the - * patch. */ -/* if (usbhid_open(x,f)) */ -/* error("[usbhid] device %d did not open",(t_int)f); */ - - usbhid_instance_count++; - - return (x); -} - -void usbhid_setup(void) -{ - usbhid_class = class_new(gensym("usbhid"), - (t_newmethod)usbhid_new, - (t_method)usbhid_free, - sizeof(t_usbhid), - CLASS_DEFAULT, - A_DEFFLOAT, - NULL); - -/* add inlet datatype methods */ -// class_addbang(usbhid_class,(t_method) usbhid_bang); - -/* add inlet message methods */ - class_addmethod(usbhid_class,(t_method) usbhid_print,gensym("print"),0); - class_addmethod(usbhid_class,(t_method) usbhid_reset,gensym("reset"),0); - class_addmethod(usbhid_class,(t_method) usbhid_refresh,gensym("refresh"),0); - class_addmethod(usbhid_class,(t_method) usbhid_debug,gensym("debug"), - A_DEFFLOAT,0); - class_addmethod(usbhid_class,(t_method) usbhid_descriptor,gensym("descriptor"), - A_GIMME,0); - class_addmethod(usbhid_class,(t_method) usbhid_set,gensym("set"), - A_DEFFLOAT,0); - class_addmethod(usbhid_class,(t_method) usbhid_get,gensym("get"), - A_DEFFLOAT,0); - class_addmethod(usbhid_class,(t_method) usbhid_open,gensym("open"), - A_DEFSYM,A_DEFSYM,0); - class_addmethod(usbhid_class,(t_method) usbhid_close,gensym("close"),0); -} - -#endif /* NOT _WIN32 */ diff --git a/usbhid.libs b/usbhid.libs deleted file mode 100644 index f4a4261..0000000 --- a/usbhid.libs +++ /dev/null @@ -1 +0,0 @@ --lusb -lhid diff --git a/usbhid/usbhid-help.pd b/usbhid/usbhid-help.pd new file mode 100644 index 0000000..08127b2 --- /dev/null +++ b/usbhid/usbhid-help.pd @@ -0,0 +1,139 @@ +#N canvas 254 84 629 549 10; +#X obj 132 376 usbhid; +#X msg 184 91 close; +#X msg 184 117 reset; +#X text 240 307 GARBAGE FOR TESTING; +#X msg 197 155 print; +#X text 317 72 Gravis/Destroyer Tiltpad; +#X text 311 43 Microsoft 5-button Mouse; +#N canvas 0 22 462 312 buttons 0; +#X obj 99 36 inlet; +#X obj 63 108 & 1; +#X obj 63 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 93 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 2 +; +#X obj 123 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +4; +#X obj 153 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +8; +#X obj 183 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +16; +#X obj 223 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +32; +#X obj 263 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 303 130 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +128; +#X obj 93 108 & 2; +#X obj 123 108 & 4; +#X obj 153 108 & 8; +#X obj 183 108 & 16; +#X obj 223 108 & 32; +#X obj 263 108 & 64; +#X obj 303 108 & 128; +#X connect 0 0 1 0; +#X connect 0 0 10 0; +#X connect 0 0 11 0; +#X connect 0 0 12 0; +#X connect 0 0 13 0; +#X connect 0 0 14 0; +#X connect 0 0 15 0; +#X connect 0 0 16 0; +#X connect 1 0 2 0; +#X connect 10 0 3 0; +#X connect 11 0 4 0; +#X connect 12 0 5 0; +#X connect 13 0 6 0; +#X connect 14 0 7 0; +#X connect 15 0 8 0; +#X connect 16 0 9 0; +#X restore 65 515 pd buttons test; +#X obj 127 462 unpack float float float float; +#X obj 44 83 metro 400; +#X obj 46 57 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X floatatom 186 499 5 0 0 0 - - -; +#X floatatom 256 500 5 0 0 0 - - -; +#X floatatom 336 495 5 0 0 0 - - -; +#X msg 171 43 open 0x045e 0x0039; +#X msg 157 13 open vendorId productId; +#X msg 176 71 open 0x047D 0x4008; +#X floatatom 125 496 5 0 0 0 - - -; +#X msg 239 273 debug \$1; +#X obj 239 251 hradio 15 1 0 10 empty empty empty 0 -6 0 8 -262144 +-1 -1 0; +#X obj 27 441 print data; +#N canvas 458 151 454 485 parsing 0; +#X obj 77 6 inlet; +#X obj 80 101 route float symbol; +#X obj 80 190 mapping/tolist; +#X obj 139 137 trigger symbol bang; +#X msg 22 139 bang; +#X obj 81 226 list trim; +#X obj 241 312 print; +#X obj 80 272 route path; +#X obj 34 328 print path-------------; +#X obj 78 31 list-abs/list-drip; +#X obj 198 51 trigger bang bang; +#X obj 247 89 print end---------; +#X connect 0 0 9 0; +#X connect 1 0 2 0; +#X connect 1 1 3 0; +#X connect 2 0 5 0; +#X connect 3 0 2 0; +#X connect 3 1 2 1; +#X connect 4 0 2 0; +#X connect 5 0 7 0; +#X connect 7 0 8 0; +#X connect 7 1 6 0; +#X connect 9 0 1 0; +#X connect 9 1 10 0; +#X connect 10 0 2 1; +#X connect 10 1 11 0; +#X restore 226 418 pd parsing; +#X text 8 122 how many bytes to read; +#X msg 194 136 refresh; +#X text 259 137 reinit and refresh device list; +#X text 233 117 resets device (don't really know what that does tho) +; +#X obj 171 419 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 171 397 route open device; +#X msg 44 104 get 4; +#X msg 82 137 get 2; +#X msg 212 179 descriptor; +#X text 291 179 get descriptor; +#X msg 219 213 descriptor 1 30 1 31 1 38; +#X text 398 212 [descriptor page# usage# ...(; +#X text 218 197 for writing to the device:; +#X msg 25 208 set 2; +#X msg 237 323 close \, open 0x045e 0x0039 \, descriptor; +#X text 183 382 <- status outlet; +#X text 21 383 data outlet ->; +#X connect 0 0 8 0; +#X connect 0 0 20 0; +#X connect 0 1 27 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 4 0 0 0; +#X connect 8 0 7 0; +#X connect 8 0 17 0; +#X connect 8 1 11 0; +#X connect 8 2 12 0; +#X connect 8 3 13 0; +#X connect 9 0 28 0; +#X connect 10 0 9 0; +#X connect 14 0 0 0; +#X connect 16 0 0 0; +#X connect 18 0 0 0; +#X connect 19 0 18 0; +#X connect 23 0 0 0; +#X connect 27 0 26 0; +#X connect 27 1 21 0; +#X connect 28 0 0 0; +#X connect 29 0 0 0; +#X connect 30 0 0 0; +#X connect 32 0 0 0; +#X connect 35 0 0 0; +#X connect 36 0 0 0; diff --git a/usbhid/usbhid.c b/usbhid/usbhid.c new file mode 100644 index 0000000..5fc069f --- /dev/null +++ b/usbhid/usbhid.c @@ -0,0 +1,782 @@ +/* --------------------------------------------------------------------------*/ +/* */ +/* Pd interface to the USB HID API using libhid, which is built on libusb */ +/* Written by Hans-Christoph Steiner */ +/* */ +/* Copyright (c) 2004 Hans-Christoph Steiner */ +/* */ +/* 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 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* See file LICENSE for further informations on licensing terms. */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* --------------------------------------------------------------------------*/ + +/* libhid hasn't been ported to Win32 yet */ +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include "m_pd.h" + +/* + * TODO: rename read, get, set messages so they make sense + * TODO: make size output work well + */ + +/* + * BUG: for some reason it skips one of the button bits + */ + + +/*------------------------------------------------------------------------------ + * INCLUDE KLUDGE + */ + +/* NOTE: included from libusb/usbi.h. UGLY, i know, but so is libusb! + * this struct doesn't seem to be defined in usb.h, only prototyped + */ +struct usb_dev_handle { + int fd; + struct usb_bus *bus; + struct usb_device *device; + int config; + int interface; + int altsetting; + void *impl_info; +}; + + +/*------------------------------------------------------------------------------ + * GLOBAL VARIABLES + */ + +/* count the number of instances of this object so that certain free() + * functions can be called only after the final instance is detroyed. */ +t_int usbhid_instance_count; + +#define HID_ID_MAX 32 +char *hid_id[HID_ID_MAX]; /* FIXME: 32 devices MAX */ +t_int hid_id_count; + +/* this array is for keeping track of whether each device has been read in + * each cycle */ +char usbhid_device_read_status[HID_ID_MAX]; + +/*------------------------------------------------------------------------------ + * CLASS DEF + */ + +typedef struct _usbhid +{ + t_object x_obj; +/* usbhid types */ + HIDInterface *x_hidinterface; + hid_return x_hid_return; +/* internal state */ + unsigned short vendor_id; // idVendor for current device + unsigned short product_id; // idProduct for current device + unsigned short debug_level; // control debug messages to the console + t_int x_device_number; + t_int x_read_element_count; + t_int *x_read_elements; + t_int x_write_element_count; + t_int *x_write_elements; + t_int report_size; // size in bytes of the HID report +/* output */ + t_atom *output; // holder for a list of atoms to be outputted + t_int output_count; // number of atoms in in x->output + t_outlet *x_data_outlet; + t_outlet *x_status_outlet; +} t_usbhid; + + +/*------------------------------------------------------------------------------ + * LOCAL DEFINES + */ + +#define USBHID_MAJOR_VERSION 0 +#define USBHID_MINOR_VERSION 0 + +static t_class *usbhid_class; + +/* for USB strings */ +#define STRING_BUFFER_LENGTH 256 + +#define SEND_PACKET_LENGTH 1 +#define RECEIVE_PACKET_LENGTH 6 +#define PATH_LENGTH 3 + + +/*------------------------------------------------------------------------------ + * SUPPORT FUNCTIONS + */ + +/* add one new atom to the list to be outputted */ +static void add_atom_to_output(t_usbhid *x, t_atom *new_atom) +{ + t_atom *new_atom_list; + + new_atom_list = (t_atom *)getbytes((x->output_count + 1) * sizeof(t_atom)); + memcpy(new_atom_list, x->output, x->output_count * sizeof(t_atom)); + freebytes(x->output, x->output_count * sizeof(t_atom)); + x->output = new_atom_list; + memcpy(x->output + x->output_count, new_atom, sizeof(t_atom)); + ++(x->output_count); +} + +static void add_symbol_to_output(t_usbhid *x, t_symbol *s) +{ + t_atom *temp_atom = getbytes(sizeof(t_atom)); + SETSYMBOL(temp_atom, s); + add_atom_to_output(x,temp_atom); + freebytes(temp_atom,sizeof(t_atom)); +} + +static void add_float_to_output(t_usbhid *x, t_float f) +{ + t_atom *temp_atom = getbytes(sizeof(t_atom)); + SETFLOAT(temp_atom, f); + add_atom_to_output(x,temp_atom); + freebytes(temp_atom,sizeof(t_atom)); +} + +static void reset_output(t_usbhid *x) +{ + if(x->output) + { + freebytes(x->output, x->output_count * sizeof(t_atom)); + x->output = NULL; + x->output_count = 0; + } +} + + +static t_int init_libhid(t_usbhid *x) +{ + if (! hid_is_initialised() ) + { + x->x_hid_return = hid_init(); + if(x->x_hid_return != HID_RET_SUCCESS) + { + error("[usbhid] hid_init failed with return code %d\n", + x->x_hid_return); + } + } + return(x->x_hid_return); +} + + +/* + * This function is used in a HIDInterfaceMatcher to iterate thru all of the + * HID devices on the USB bus + */ +static bool device_iterator (struct usb_dev_handle const* usbdev, void* custom, + unsigned int length) +{ + bool ret = false; + t_int i; + char current_dev_path[10]; + + /* only here to prevent the unused warning */ + /* TODO remove */ + length = *((unsigned long*)custom); + + /* Obtain the device's full path */ + sprintf(current_dev_path, "%s/%s", usbdev->bus->dirname, usbdev->device->filename); + + /* Check if we already saw this dev */ + for ( i = 0 ; ( hid_id[i] != NULL ) ; i++ ) + { + if (!strcmp(hid_id[i], current_dev_path ) ) + break; + } + + /* Append device to the list if needed */ + if (hid_id[i] == NULL) + { + hid_id[i] = (char *) malloc(strlen(usbdev->device->filename) + strlen(usbdev->bus->dirname) ); + sprintf(hid_id[i], "%s/%s", usbdev->bus->dirname, usbdev->device->filename); + } + else /* device already seen */ + { + return false; + } + + /* Filter non HID device */ + if ( (usbdev->device->descriptor.bDeviceClass == 0) /* Class defined at interface level */ + && usbdev->device->config + && usbdev->device->config->interface->altsetting->bInterfaceClass == USB_CLASS_HID) + { + + post("bus %s device %s: %d %d", + usbdev->bus->dirname, + usbdev->device->filename, + usbdev->device->descriptor.idVendor, + usbdev->device->descriptor.idProduct); + ret = true; + } + + else + { + ret = false; + } + + + return ret; +} + +/* -------------------------------------------------------------------------- */ +/* This function is used in a HIDInterfaceMatcher in order to match devices by + * serial number. + */ +/* static bool match_serial_number(struct usb_dev_handle* usbdev, void* custom, unsigned int length) */ +/* { */ +/* bool ret; */ +/* char* buffer = (char*)malloc(length); */ +/* usb_get_string_simple(usbdev, usb_device(usbdev)->descriptor.iSerialNumber, */ +/* buffer, length); */ +/* ret = strncmp(buffer, (char*)custom, length) == 0; */ +/* free(buffer); */ +/* return ret; */ +/* } */ + + +/* -------------------------------------------------------------------------- */ +/* static bool get_device_by_number(struct usb_dev_handle* usbdev, */ +/* void* custom, */ +/* unsigned int length) */ +/* { */ +/* bool ret; */ + + +/* return ret; */ +/* } */ + + +/* -------------------------------------------------------------------------- */ +static t_int* make_hid_path(t_int element_count, t_int argc, t_atom *argv) +{ + t_int i; + t_int *return_array = NULL; + + post("element_count %d",element_count); + return_array = (t_int *) getbytes(sizeof(t_int) * element_count); + for(i=0; i < element_count; ++i) + { +/* + * A usbhid path component is 32 bits, the high 16 bits identify the usage page, + * and the low 16 bits the item number. + */ + return_array[i] = + (atom_getintarg(i*2,argc,argv) << 16) + atom_getintarg(i*2+1,argc,argv); +/* TODO: print error if a symbol is found in the data list */ + } + return return_array; +} + + +static t_int get_device_string(HIDInterface *hidif, char *device_string) +{ + int length; + t_int ret = 0; + char buffer[STRING_BUFFER_LENGTH]; + + if ( !hid_is_opened(hidif) ) + return(0); + + if (hidif->device->descriptor.iManufacturer) { + length = usb_get_string_simple(hidif->dev_handle, + hidif->device->descriptor.iManufacturer, + buffer, + STRING_BUFFER_LENGTH); + if (length > 0) + { + strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string)); + strncat(device_string, " ",1); + ret = 1; + } + else + { + post("(unable to fetch manufacturer string)"); + } + } + + if (hidif->device->descriptor.iProduct) { + length = usb_get_string_simple(hidif->dev_handle, + hidif->device->descriptor.iProduct, + buffer, + STRING_BUFFER_LENGTH); + if (length > 0) + { + strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string)); + strncat(device_string, " ",1); + ret = 1; + } + else + { + post("(unable to fetch product string)"); + } + } + + if (hidif->device->descriptor.iSerialNumber) { + length = usb_get_string_simple(hidif->dev_handle, + hidif->device->descriptor.iSerialNumber, + buffer, + STRING_BUFFER_LENGTH); + if (length > 0) + strncat(device_string, buffer, STRING_BUFFER_LENGTH - strlen(device_string)); + else + post("(unable to fetch product string)"); + } + + return ret; +} + + +/*------------------------------------------------------------------------------ + * IMPLEMENTATION + */ + + +/* -------------------------------------------------------------------------- */ +static void usbhid_close(t_usbhid *x) +{ + if(x->debug_level) post("usbhid_close"); + t_int ret; + char string_buffer[STRING_BUFFER_LENGTH]; + + if ( hid_is_opened(x->x_hidinterface) ) + { + ret = get_device_string(x->x_hidinterface,string_buffer); + x->x_hid_return = hid_close(x->x_hidinterface); + if (x->x_hid_return == HID_RET_SUCCESS) + { + if (ret) + post("[usbhid]: closed %s",string_buffer); + else + post("[usbhid]: closed device"); + reset_output(x); + add_float_to_output(x,0); + outlet_anything(x->x_status_outlet, gensym("open"), + x->output_count, x->output); + } + else + { + error("[usbhid] could not close %d, error #%d",x->x_device_number,x->x_hid_return); + } + } +} + + +/* -------------------------------------------------------------------------- */ +static void usbhid_open(t_usbhid *x, t_symbol *vendor_id_hex, t_symbol *product_id_hex) +{ + if(x->debug_level) post("usbhid_open"); + char string_buffer[STRING_BUFFER_LENGTH]; + + if( init_libhid(x) != HID_RET_SUCCESS ) return; + +/* convert hex symbols to ints */ + x->vendor_id = (unsigned short) strtol(vendor_id_hex->s_name, NULL, 16); + x->product_id = (unsigned short) strtol(product_id_hex->s_name, NULL, 16); + if( hid_is_opened(x->x_hidinterface) ) + { + if( (x->vendor_id == x->x_hidinterface->device->descriptor.idVendor) && + (x->product_id == x->x_hidinterface->device->descriptor.idProduct)) + { + post("[usbhid] device already opened"); + return; + } + else + { + usbhid_close(x); + } + } + + if( !hid_is_opened(x->x_hidinterface) ) + { + HIDInterfaceMatcher matcher = { x->vendor_id, + x->product_id, + NULL, + NULL, + 0 }; + x->x_hid_return = hid_force_open(x->x_hidinterface, 0, &matcher, 3); + if (x->x_hid_return == HID_RET_SUCCESS) + { + if (get_device_string(x->x_hidinterface,string_buffer)) + post("[usbhid]: opened %s",string_buffer); + reset_output(x); + add_float_to_output(x,1); + outlet_anything(x->x_status_outlet, gensym("open"), + x->output_count, x->output); + } + else + { + error("[usbhid] hid_force_open failed with return code %d\n", + x->x_hid_return); + } + } +} + + +/* -------------------------------------------------------------------------- */ +static void usbhid_set(t_usbhid *x, t_float length_arg) +{ + if(x->debug_level) post("usbhid_set"); + int packet_bytes = (int)length_arg; + char packet[packet_bytes]; + + if ( !hid_is_opened(x->x_hidinterface) ) + { + error("[usbhid] device not open, can't set data"); + return; + } + x->x_hid_return = hid_set_output_report(x->x_hidinterface, + x->x_write_elements, + x->x_write_element_count, + packet, + length_arg); + if (x->x_hid_return != HID_RET_SUCCESS) + { + error("[usbhid] hid_get_input_report failed with return code %d\n", + x->x_hid_return); + reset_output(x); + add_float_to_output(x, x->x_hid_return); + outlet_anything(x->x_status_outlet, gensym("setError"), + x->output_count, x->output); + } +} + +/* -------------------------------------------------------------------------- */ +static void usbhid_get(t_usbhid *x, t_float length_arg) +{ + if(x->debug_level) post("usbhid_get"); + int i; + int packet_bytes = (int)length_arg; + char packet[packet_bytes]; + + if ( !hid_is_opened(x->x_hidinterface) ) + { + error("[usbhid] device not open, can't get data"); + return; + } + x->x_hid_return = hid_get_input_report(x->x_hidinterface, + NULL, + x->x_read_element_count, + packet, + length_arg); + if (x->x_hid_return != HID_RET_SUCCESS) + { + error("[usbhid] hid_get_input_report failed with return code %d\n", + x->x_hid_return); + reset_output(x); + add_float_to_output(x, x->x_hid_return); + outlet_anything(x->x_status_outlet, gensym("getError"), + x->output_count, x->output); + } + + reset_output(x); + for(i=0; ix_data_outlet, &s_list, x->output_count, x->output); + post("x->x_read_elements %d",x->x_read_elements); +} + + +/* -------------------------------------------------------------------------- */ +/* reinit libhid to get update the list of attached devices */ +static void usbhid_refresh(t_usbhid *x) +{ + x->x_hid_return = hid_cleanup(); + if (x->x_hid_return != HID_RET_SUCCESS) + error("[usbhid] hid_cleanup failed with return code %d\n", + x->x_hid_return); + if( init_libhid(x) != HID_RET_SUCCESS ) return; +} + + +/* -------------------------------------------------------------------------- */ +/* set the HID packet for which elements to read */ +static void usbhid_set_read(t_usbhid *x, int argc, t_atom *argv) +{ + if(x->debug_level) post("usbhid_set_read"); + t_int i; + + x->x_read_element_count = argc / 2; + x->x_read_elements = make_hid_path(x->x_read_element_count, argc, argv); + post("x_read_element_count %d",x->x_read_element_count); + for(i=0;ix_read_element_count;++i) + post("x_read_elements %d: %d",i,x->x_read_elements[i]); +} + + +/* -------------------------------------------------------------------------- */ +/* convert a list to a HID packet and set it */ +/* set the HID packet for which elements to write */ +static void usbhid_set_descriptor(t_usbhid *x, int argc, t_atom *argv) +{ + if(x->debug_level) post("usbhid_descriptor"); +/* int const PATH_IN[PATH_LENGTH] = { 0xffa00001, 0xffa00002, 0xffa10003 }; */ +// int const PATH_OUT[3] = { 0x00010002, 0x00010001, 0x00010030 }; + t_int i; + + x->x_write_element_count = argc / 2; + x->x_write_elements = make_hid_path(x->x_write_element_count, argc, argv); + post("x_write_element_count %d",x->x_write_element_count); + for(i=0;ix_write_element_count;++i) + post("x_write_elements %d: %d",i,x->x_write_elements[i]); +} + + + +/* -------------------------------------------------------------------------- */ +static void usbhid_get_descriptor(t_usbhid *x) +{ + if(x->debug_level) post("usbhid_get"); + unsigned int i = 0; + t_int input_size = 0; + t_int output_size = 0; + t_int feature_size = 0; + + if (!hid_is_opened(x->x_hidinterface)) { + error("[usbget] cannot dump tree of unopened HIDinterface."); + } + else + { + post("[usbhid] parse tree of HIDInterface %s:\n", x->x_hidinterface->id); + reset_output(x); + while (HIDParse(x->x_hidinterface->hid_parser, x->x_hidinterface->hid_data)) { + add_symbol_to_output(x, gensym("path")); + switch(x->x_hidinterface->hid_data->Type) + { + case 0x80: + add_symbol_to_output(x, gensym("input")); + input_size = input_size + x->x_hidinterface->hid_data->Size; + break; + case 0x90: + add_symbol_to_output(x, gensym("output")); + output_size = output_size + x->x_hidinterface->hid_data->Size; + break; + case 0xb0: + add_symbol_to_output(x, gensym("feature")); + feature_size = feature_size + x->x_hidinterface->hid_data->Size; + break; + default: add_symbol_to_output(x, gensym("UNKNOWN_TYPE")); + } + add_float_to_output(x, x->x_hidinterface->hid_data->Size); + add_float_to_output(x, x->x_hidinterface->hid_data->Offset); + for (i = 0; i < x->x_hidinterface->hid_data->Path.Size; ++i) { + add_symbol_to_output(x, gensym("usage")); + add_float_to_output(x, x->x_hidinterface->hid_data->Path.Node[i].UPage); + add_float_to_output(x, x->x_hidinterface->hid_data->Path.Node[i].Usage); + post("page: 0x%04x\t%d\t\tusage: 0x%04x\t%d", + x->x_hidinterface->hid_data->Path.Node[i].UPage, + x->x_hidinterface->hid_data->Path.Node[i].UPage, + x->x_hidinterface->hid_data->Path.Node[i].Usage, + x->x_hidinterface->hid_data->Path.Node[i].Usage); + } + post("type: 0x%02x\n", x->x_hidinterface->hid_data->Type); + add_symbol_to_output(x, gensym("logical")); + add_float_to_output(x, x->x_hidinterface->hid_data->LogMin); + add_float_to_output(x, x->x_hidinterface->hid_data->LogMax); + } + add_symbol_to_output(x, gensym("totalSize")); + add_float_to_output(x, input_size); + add_float_to_output(x, output_size); + add_float_to_output(x, feature_size); + outlet_anything(x->x_status_outlet, gensym("device"), + x->output_count, x->output); + } +} + +/* -------------------------------------------------------------------------- */ +static void usbhid_descriptor(t_usbhid *x, t_symbol *s, int argc, t_atom *argv) +{ + if(s == gensym("descriptor")) // get rid of unused s warning + { + if(argc) + usbhid_set_descriptor(x,argc,argv); + else + usbhid_get_descriptor(x); + } +} + +/* -------------------------------------------------------------------------- */ +static void usbhid_print(t_usbhid *x) +{ + if(x->debug_level) post("usbhid_print"); + t_int i; + char string_buffer[STRING_BUFFER_LENGTH]; +/* t_atom event_data[3]; */ + + for ( i = 0 ; ( hid_id[i] != NULL ) ; i++ ) + { + if( hid_id[i] != NULL ) + post("hid_id[%d]: %s",i,hid_id[i]); + } + if(get_device_string(x->x_hidinterface,string_buffer)) + post("%s is currently open",string_buffer); + + x->x_hid_return = hid_dump_tree(stdout, x->x_hidinterface); + if (x->x_hid_return != HID_RET_SUCCESS) { + fprintf(stderr, "hid_dump_tree failed with return code %d\n", x->x_hid_return); + return; + } + +/* SETSYMBOL(event_data, gensym(type)); /\* type *\/ */ +/* SETSYMBOL(event_data + 1, gensym(code)); /\* code *\/ */ +/* SETSYMBOL(event_data + 2, value); /\* value *\/ */ +// outlet_list(x->x_status_outlet, &s_list, +} + + +/* -------------------------------------------------------------------------- */ +static void usbhid_reset(t_usbhid *x) +{ + if(x->debug_level) post("usbhid_reset"); + + hid_reset_HIDInterface(x->x_hidinterface); +} + + +/* -------------------------------------------------------------------------- */ +static void usbhid_debug(t_usbhid *x, t_float f) +{ + x->debug_level = f; + + switch(x->debug_level) + { + case 0: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_NONE); break; + case 1: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_ERRORS); break; + case 2: hid_set_usb_debug(0); + hid_set_debug(HID_DEBUG_ERRORS | HID_DEBUG_WARNINGS); break; + case 3: hid_set_usb_debug(0); + hid_set_debug(HID_DEBUG_ERRORS | HID_DEBUG_WARNINGS | HID_DEBUG_NOTICES); break; + case 4: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_NOTRACES); break; + case 5: hid_set_usb_debug(0); hid_set_debug(HID_DEBUG_ALL); break; + default: + hid_set_usb_debug(x->debug_level - 5); hid_set_debug(HID_DEBUG_ALL); break; + } +} + + +/* -------------------------------------------------------------------------- */ +static void usbhid_free(t_usbhid* x) +{ + if(x->debug_level) post("usbhid_free"); + + usbhid_close(x); + + freebytes(x->x_read_elements,sizeof(t_int) * x->x_read_element_count); + freebytes(x->x_write_elements,sizeof(t_int) * x->x_write_element_count); + + if(x->debug_level) + post("[usbhid] freeing instance %d",usbhid_instance_count); + hid_delete_HIDInterface(&(x->x_hidinterface)); + if(usbhid_instance_count <= 1) + { + post("[usbhid] freeing last instance"); + x->x_hid_return = hid_cleanup(); + if (x->x_hid_return != HID_RET_SUCCESS) + error("[usbhid] hid_cleanup failed with return code %d\n", + x->x_hid_return); + } + + usbhid_instance_count--; +} + + + +/* -------------------------------------------------------------------------- */ +static void *usbhid_new(t_float f) +{ + t_int i; + HIDInterfaceMatcher matcher; + t_usbhid *x = (t_usbhid *)pd_new(usbhid_class); + + if(x->debug_level) post("usbhid_new"); + +/* only display the version when the first instance is loaded */ + if(!usbhid_instance_count) + post("[usbhid] %d.%d, written by Hans-Christoph Steiner ", + USBHID_MAJOR_VERSION, USBHID_MINOR_VERSION); + + /* create anything outlet used for HID data */ + x->x_data_outlet = outlet_new(&x->x_obj, 0); + x->x_status_outlet = outlet_new(&x->x_obj, 0); + + /* turn off the flood of libhid debug messages by default */ + hid_set_debug(HID_DEBUG_NONE); + hid_set_debug_stream(stdout); + hid_set_usb_debug(0); + + /* data init */ + x->output = NULL; + x->output_count = 0; + for (i = 0 ; i < HID_ID_MAX ; i++) + hid_id[i] = NULL; + + x->x_hidinterface = hid_new_HIDInterface(); + matcher.vendor_id = HID_ID_MATCH_ANY; + matcher.product_id = HID_ID_MATCH_ANY; + matcher.matcher_fn = device_iterator; + + x->x_device_number = f; + +/* Open the device and save settings. If there is an error, return the object + * anyway, so that the inlets and outlets are created, thus not breaking the + * patch. */ +/* if (usbhid_open(x,f)) */ +/* error("[usbhid] device %d did not open",(t_int)f); */ + + usbhid_instance_count++; + + return (x); +} + +void usbhid_setup(void) +{ + usbhid_class = class_new(gensym("usbhid"), + (t_newmethod)usbhid_new, + (t_method)usbhid_free, + sizeof(t_usbhid), + CLASS_DEFAULT, + A_DEFFLOAT, + NULL); + +/* add inlet datatype methods */ +// class_addbang(usbhid_class,(t_method) usbhid_bang); + +/* add inlet message methods */ + class_addmethod(usbhid_class,(t_method) usbhid_print,gensym("print"),0); + class_addmethod(usbhid_class,(t_method) usbhid_reset,gensym("reset"),0); + class_addmethod(usbhid_class,(t_method) usbhid_refresh,gensym("refresh"),0); + class_addmethod(usbhid_class,(t_method) usbhid_debug,gensym("debug"), + A_DEFFLOAT,0); + class_addmethod(usbhid_class,(t_method) usbhid_descriptor,gensym("descriptor"), + A_GIMME,0); + class_addmethod(usbhid_class,(t_method) usbhid_set,gensym("set"), + A_DEFFLOAT,0); + class_addmethod(usbhid_class,(t_method) usbhid_get,gensym("get"), + A_DEFFLOAT,0); + class_addmethod(usbhid_class,(t_method) usbhid_open,gensym("open"), + A_DEFSYM,A_DEFSYM,0); + class_addmethod(usbhid_class,(t_method) usbhid_close,gensym("close"),0); +} + +#endif /* NOT _WIN32 */ diff --git a/usbhid/usbhid.libs b/usbhid/usbhid.libs new file mode 100644 index 0000000..f4a4261 --- /dev/null +++ b/usbhid/usbhid.libs @@ -0,0 +1 @@ +-lusb -lhid -- cgit v1.2.1