From d82e6551de2b9f3215fd5f58085097d47a6864b9 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 30 Nov 2006 05:53:41 +0000 Subject: did lots of renaming to the new [hidio] name, removed a little bit of cruft. Builds on Mac OS X, but doesn't load yet :-/. hidio_setup() gets called successfully, but for some reason hidio_new() does not seem to get called svn path=/trunk/externals/io/hidio/; revision=6533 --- hidio.c | 485 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 hidio.c (limited to 'hidio.c') diff --git a/hidio.c b/hidio.c new file mode 100644 index 0000000..d43e0df --- /dev/null +++ b/hidio.c @@ -0,0 +1,485 @@ +/* --------------------------------------------------------------------------*/ +/* */ +/* interface to native HID (Human Interface Devices) API */ +/* Written by Hans-Christoph Steiner */ +/* */ +/* Copyright (c) 2004-2006 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. */ +/* */ +/* --------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +#include "hidio.h" + +/*------------------------------------------------------------------------------ + * LOCAL DEFINES + */ + +//#define DEBUG(x) +#define DEBUG(x) x + +unsigned short global_debug_level = 0; + +static t_class *hidio_class; + +/*------------------------------------------------------------------------------ + * FUNCTION PROTOTYPES + */ + +//static void hidio_poll(t_hidio *x, t_float f); +static void hidio_open(t_hidio *x, t_symbol *s, int argc, t_atom *argv); +//static t_int hidio_close(t_hidio *x); +//static t_int hidio_read(t_hidio *x,int fd); +//static void hidio_float(t_hidio* x, t_floatarg f); + + +/*------------------------------------------------------------------------------ + * SUPPORT FUNCTIONS + */ + +void debug_print(t_int message_debug_level, const char *fmt, ...) +{ + if(message_debug_level <= global_debug_level) + { + char buf[MAXPDSTRING]; + va_list ap; + //t_int arg[8]; + va_start(ap, fmt); + vsnprintf(buf, MAXPDSTRING-1, fmt, ap); + post(buf); + va_end(ap); + } +} + +void debug_error(t_hidio *x, t_int message_debug_level, const char *fmt, ...) +{ + if(message_debug_level <= global_debug_level) + { + char buf[MAXPDSTRING]; + va_list ap; + //t_int arg[8]; + va_start(ap, fmt); + vsnprintf(buf, MAXPDSTRING-1, fmt, ap); + pd_error(x, buf); + va_end(ap); + } +} + + +static void output_status(t_hidio *x, t_symbol *selector, t_float output_value) +{ + t_atom *output_atom = getbytes(sizeof(t_atom)); + SETFLOAT(output_atom, output_value); + outlet_anything( x->x_status_outlet, selector, 1, output_atom); + freebytes(output_atom,sizeof(t_atom)); +} + +static void output_open_status(t_hidio *x) +{ + output_status(x, gensym("open"), x->x_device_open); +} + +static void output_device_number(t_hidio *x) +{ + output_status(x, gensym("device"), x->x_device_number); +} + +static void output_poll_time(t_hidio *x) +{ + output_status(x, gensym("poll"), x->x_delay); +} + +static void output_device_count(t_hidio *x) +{ + output_status(x, gensym("total"), device_count); +} + +static void output_element_ranges(t_hidio *x) +{ + if( (x->x_device_number > -1) && (x->x_device_open) ) + { + unsigned int i; + t_atom output_data[4]; + + for(i=0;ix_device_number];++i) + { + SETSYMBOL(output_data, element[x->x_device_number][i]->type); + SETSYMBOL(output_data + 1, element[x->x_device_number][i]->name); + SETFLOAT(output_data + 2, element[x->x_device_number][i]->min); + SETFLOAT(output_data + 3, element[x->x_device_number][i]->max); + outlet_anything(x->x_status_outlet, gensym("range"), 4, output_data); + } + } +} + + +static unsigned int name_to_usage(char *usage_name) +{ // output usagepage << 16 + usage + if(strcmp(usage_name,"pointer") == 0) return(0x00010001); + if(strcmp(usage_name,"mouse") == 0) return(0x00010002); + if(strcmp(usage_name,"joystick") == 0) return(0x00010004); + if(strcmp(usage_name,"gamepad") == 0) return(0x00010005); + if(strcmp(usage_name,"keyboard") == 0) return(0x00010006); + if(strcmp(usage_name,"keypad") == 0) return(0x00010007); + if(strcmp(usage_name,"multiaxiscontroller") == 0) return(0x00010008); + return(0); +} + + +static short get_device_number_from_arguments(int argc, t_atom *argv) +{ + short device_number = -1; + unsigned short device_type_instance; + unsigned int usage; + unsigned short vendor_id; + unsigned short product_id; + char device_type_string[MAXPDSTRING] = ""; + t_symbol *first_argument; + t_symbol *second_argument; + + if(argc == 1) + { + first_argument = atom_getsymbolarg(0,argc,argv); + if(first_argument == &s_) + { // single float arg means device # + post("first_argument == &s_"); + device_number = (short) atom_getfloatarg(0,argc,argv); + if(device_number < 0) device_number = -1; + debug_print(LOG_DEBUG,"[hidio] setting device# to %d",device_number); + } + else + { // single symbol arg means first instance of a device type + atom_string(argv, device_type_string, MAXPDSTRING-1); + usage = name_to_usage(device_type_string); + device_number = get_device_number_from_usage(0, usage >> 16, + usage & 0xffff); + debug_print(LOG_INFO,"[hidio] using 0x%04x 0x%04x for %s", + usage >> 16, usage & 0xffff, device_type_string); + } + } + else if(argc == 2) + { + first_argument = atom_getsymbolarg(0,argc,argv); + second_argument = atom_getsymbolarg(1,argc,argv); + if( second_argument == &s_ ) + { /* a symbol then a float means match on usage */ + atom_string(argv, device_type_string, MAXPDSTRING-1); + usage = name_to_usage(device_type_string); + device_type_instance = atom_getfloatarg(1,argc,argv); + debug_print(LOG_DEBUG,"[hidio] looking for %s at #%d", + device_type_string, device_type_instance); + device_number = get_device_number_from_usage(device_type_instance, + usage >> 16, + usage & 0xffff); + } + else + { /* two symbols means idVendor and idProduct in hex */ + vendor_id = + (unsigned short) strtol(first_argument->s_name, NULL, 16); + product_id = + (unsigned short) strtol(second_argument->s_name, NULL, 16); + device_number = get_device_number_by_id(vendor_id,product_id); + } + } + return(device_number); +} + + +void hidio_output_event(t_hidio *x, t_hid_element *output_data) +{ + if( (output_data->value != output_data->previous_value) || + (output_data->relative) ) // relative data should always be output + { + t_atom event_data[3]; + SETSYMBOL(event_data, output_data->name); + SETFLOAT(event_data + 1, output_data->instance); + SETFLOAT(event_data + 2, output_data->value); + outlet_anything(x->x_data_outlet,output_data->type,3,event_data); + } +} + + +/* stop polling the device */ +static void stop_poll(t_hidio* x) +{ + debug_print(LOG_DEBUG,"stop_poll"); + + if (x->x_started) + { + clock_unset(x->x_clock); + debug_print(LOG_INFO,"[hidio] polling stopped"); + x->x_started = 0; + } +} + +/*------------------------------------------------------------------------------ + * METHODS FOR [hidio]'s MESSAGES + */ + + +void hidio_poll(t_hidio* x, t_float f) +{ + debug_print(LOG_DEBUG,"hidio_poll"); + +/* if the user sets the delay less than 2, set to block size */ + if( f > 2 ) + x->x_delay = (t_int)f; + else if( f > 0 ) //TODO make this the actual time between message processing + x->x_delay = 1.54; + if(x->x_device_number > -1) + { + if(!x->x_device_open) + hidio_open(x,gensym("open"),0,NULL); + if(!x->x_started) + { + clock_delay(x->x_clock, x->x_delay); + debug_print(LOG_DEBUG,"[hidio] polling started"); + x->x_started = 1; + } + } +} + +static void hidio_set_from_float(t_hidio *x, t_floatarg f) +{ +/* values greater than 1 set the polling delay time */ +/* 1 and 0 for start/stop so you can use a [tgl] */ + if(f > 1) + { + x->x_delay = (t_int)f; + hidio_poll(x,f); + } + else if(f == 1) + { + if(! x->x_started) + hidio_poll(x,f); + } + else if(f == 0) + { + stop_poll(x); + } +} + +/* close the device */ +t_int hidio_close(t_hidio *x) +{ + debug_print(LOG_DEBUG,"hidio_close"); + +/* just to be safe, stop it first */ + stop_poll(x); + + if(! hidio_close_device(x)) + { + debug_print(LOG_INFO,"[hidio] closed device %d",x->x_device_number); + x->x_device_open = 0; + return (0); + } + + return (1); +} + + +/* hidio_open behavoir + * current state action + * --------------------------------------- + * closed / same device open + * open / same device no action + * closed / different device open + * open / different device close open + */ +static void hidio_open(t_hidio *x, t_symbol *s, int argc, t_atom *argv) +{ + debug_print(LOG_DEBUG,"hid_%s",s->s_name); +/* store running state to be restored after the device has been opened */ + t_int started = x->x_started; + + short device_number = get_device_number_from_arguments(argc, argv); + if(device_number > -1) + { + if( (device_number != x->x_device_number) && (x->x_device_open) ) + hidio_close(x); + if(! x->x_device_open) + { + if(hidio_open_device(x,device_number)) + error("[hidio] can not open device %d",device_number); + else + x->x_device_open = 1; + } + } + else debug_print(LOG_WARNING,"[hidio] device does not exist"); +/* restore the polling state so that when I [tgl] is used to start/stop [hidio], + * the [tgl]'s state will continue to accurately reflect [hidio]'s state */ + if(started) + hidio_set_from_float(x,x->x_delay); + debug_print(LOG_DEBUG,"[hidio] set device# to %d",device_number); + output_open_status(x); + output_device_number(x); +} + + +t_int hidio_read(t_hidio *x, int fd) +{ +// debug_print(LOG_DEBUG,"hidio_read"); + unsigned int i; + double right_now = clock_getlogicaltime(); + t_hid_element *current_element; + + if(right_now > last_execute_time[x->x_device_number]) + { + hidio_get_events(x); + last_execute_time[x->x_device_number] = right_now; +/* post("executing: instance %d/%d at %ld", + x->x_instance, hidio_instance_count, right_now);*/ + } + for(i=0; i< element_count[x->x_device_number]; ++i) + { + current_element = element[x->x_device_number][i]; + if(current_element->previous_value != current_element->value) + { + hidio_output_event(x, current_element); + if(!current_element->relative) + current_element->previous_value = current_element->value; + } + } + if (x->x_started) + { + clock_delay(x->x_clock, x->x_delay); + } + + // TODO: why is this 1? + return 1; +} + +static void hidio_info(t_hidio *x) +{ + output_open_status(x); + output_device_number(x); + output_device_count(x); + output_poll_time(x); + output_element_ranges(x); + hidio_platform_specific_info(x); +} + +static void hidio_float(t_hidio* x, t_floatarg f) +{ + debug_print(LOG_DEBUG,"hid_float"); + + hidio_set_from_float(x,f); +} + +static void hidio_debug(t_hidio *x, t_float f) +{ + global_debug_level = f; +} + + +/*------------------------------------------------------------------------------ + * system functions + */ +static void hidio_free(t_hidio* x) +{ + debug_print(LOG_DEBUG,"hidio_free"); + + hidio_close(x); + clock_free(x->x_clock); + hidio_instance_count--; + + hidio_platform_specific_free(x); +} + +/* create a new instance of this class */ +static void *hidio_new(t_symbol *s, int argc, t_atom *argv) +{ + DEBUG(post("hidio_new");); + t_hidio *x = (t_hidio *)pd_new(hidio_class); + unsigned int i; + +#if !defined(__linux__) && !defined(__APPLE__) + error(" !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!"); + error(" This is a dummy, since this object only works GNU/Linux and MacOS X!"); + error(" !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!"); +#endif + + /* init vars */ + global_debug_level = 9; /* high numbers here means see more messages */ + x->x_has_ff = 0; + x->x_device_open = 0; + x->x_started = 0; + x->x_delay = DEFAULT_DELAY; + for(i=0; ix_clock = clock_new(x, (t_method)hidio_read); + + /* 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); + + x->x_device_number = get_device_number_from_arguments(argc, argv); + + x->x_instance = hidio_instance_count; + hidio_instance_count++; + + return (x); +} + +void hidio_setup(void) +{ + hidio_class = class_new(gensym("hidin"), + (t_newmethod)hidio_new, + (t_method)hidio_free, + sizeof(t_hidio), + CLASS_DEFAULT, + A_GIMME,0); + + /* add inlet datatype methods */ + class_addfloat(hidio_class,(t_method) hidio_float); + class_addbang(hidio_class,(t_method) hidio_read); +/* class_addanything(hidio_class,(t_method) hidio_anything); */ + + /* add inlet message methods */ +/* class_addmethod(hidio_class,(t_method) hidio_debug,gensym("debug"),A_DEFFLOAT,0); + class_addmethod(hidio_class,(t_method) hidio_build_device_list,gensym("refresh"),0); + class_addmethod(hidio_class,(t_method) hidio_print,gensym("print"),0); + class_addmethod(hidio_class,(t_method) hidio_info,gensym("info"),0); + class_addmethod(hidio_class,(t_method) hidio_open,gensym("open"),A_GIMME,0); + class_addmethod(hidio_class,(t_method) hidio_close,gensym("close"),0); + class_addmethod(hidio_class,(t_method) hidio_poll,gensym("poll"),A_DEFFLOAT,0); + /* force feedback messages */ +/* class_addmethod(hidio_class,(t_method) hidio_ff_autocenter, + gensym("ff_autocenter"),A_DEFFLOAT,0); + class_addmethod(hidio_class,(t_method) hidio_ff_gain,gensym("ff_gain"),A_DEFFLOAT,0); + class_addmethod(hidio_class,(t_method) hidio_ff_motors,gensym("ff_motors"),A_DEFFLOAT,0); + class_addmethod(hidio_class,(t_method) hidio_ff_continue,gensym("ff_continue"),0); + class_addmethod(hidio_class,(t_method) hidio_ff_pause,gensym("ff_pause"),0); + class_addmethod(hidio_class,(t_method) hidio_ff_reset,gensym("ff_reset"),0); + class_addmethod(hidio_class,(t_method) hidio_ff_stopall,gensym("ff_stopall"),0); + /* ff tests */ +/* class_addmethod(hidio_class,(t_method) hidio_ff_fftest,gensym("fftest"),A_DEFFLOAT,0); + class_addmethod(hidio_class,(t_method) hidio_ff_print,gensym("ff_print"),0); +*/ + + post("[hidio] %d.%d, written by Hans-Christoph Steiner ", + HIDIO_MAJOR_VERSION, HIDIO_MINOR_VERSION); + post("\tcompiled on "__DATE__" at "__TIME__ " "); + post("arg!!!!!!"); +} + -- cgit v1.2.1