aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--TODO10
-rw-r--r--hidio-help.pd17
-rw-r--r--hidio.c347
-rw-r--r--hidio.h24
-rw-r--r--hidio_darwin.c146
-rw-r--r--hidio_linux.c7
-rw-r--r--test/latency_test.pd22
-rw-r--r--test/test_instance.pd93
-rw-r--r--test/test_instance_GUI.pd26
10 files changed, 346 insertions, 354 deletions
diff --git a/Makefile b/Makefile
index 78d1860..98be310 100644
--- a/Makefile
+++ b/Makefile
@@ -15,14 +15,18 @@ test_locations:
# for emacs
etags:
- etags ../../../pd/src/*.h *.[ch] linux/input.h
+ etags ../../../pd/src/*.h *.[ch] linux/input.h /usr/include/stdlib.h \
+ /usr/include/time.h /usr/include/stdio.h
make etags_`uname -s`
etags_Darwin:
etags -a HID\ Utilities\ Source/*.[ch] \
/System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \
/System/Library/Frameworks/Carbon.framework/Headers/*.h \
- /System/Library/Frameworks/IOKit.framework/Headers/hid*/*.[ch]
+ /System/Library/Frameworks/CoreServices.framework/Headers/*.h \
+ /System/Library/Frameworks/IOKit.framework/Headers/*.[ch] \
+ /System/Library/Frameworks/IOKit.framework/Headers/hid*/*.[ch] \
+ /usr/include/mach/*.h
etags_Linux:
etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
diff --git a/TODO b/TODO
index f3e32e2..c883ae2 100644
--- a/TODO
+++ b/TODO
@@ -52,10 +52,12 @@ compare against
______________________________________________________________________________
= make only the first executed instance fetch the data
- the function is ugen_getsortno() -- returns
-an integer which increases eachtime DSP is restarted. You can add the
-function call (to the ugen chain for instance) each time you see
-ugen_getsortno() return an integer greater than the previous one you've
+- double right_now = clock_getlogicaltime();
+ this only works when instances are in the same patch, not when instances are
+ in different patches
+
+- implement event output data structure
+
______________________________________________________________________________
= output one value per poll
diff --git a/hidio-help.pd b/hidio-help.pd
index 0cace51..592fc72 100644
--- a/hidio-help.pd
+++ b/hidio-help.pd
@@ -1,4 +1,4 @@
-#N canvas 157 38 862 587 10;
+#N canvas 157 38 878 603 10;
#X floatatom 27 445 5 0 0 0 - - -;
#X floatatom 83 445 5 0 0 0 - - -;
#X obj 191 164 tgl 35 0 empty empty empty 0 -6 0 8 -24198 -1 -1 25
@@ -14,7 +14,7 @@
#X text 435 117 refresh device list;
#X text 537 487 For more info:;
#X text 266 557 released under the GNU GPL;
-#X text 472 544 $Revision: 1.3 $$Date: 2006-12-08 06:33:26 $;
+#X text 472 544 $Revision: 1.4 $$Date: 2006-12-31 22:49:16 $;
#X text 473 557 $Author: eighthave $;
#X msg 436 201 poll 20;
#X msg 374 201 poll 2;
@@ -270,7 +270,7 @@ of it could change without notice !!!;
1;
#X obj 459 508 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
1;
-#X msg 25 155 debug 0;
+#X msg 25 155 debug 9;
#X msg 298 145 info;
#N canvas 743 25 411 235 see 0;
#N canvas 108 318 543 264 route 0;
@@ -398,10 +398,10 @@ IDs (it is not case sensitive):;
#X text 49 543 (C) Copyright 2004 Hans-Christoph Steiner <hans@at.or.at>
;
#N canvas 162 133 570 420 serin 0;
-#X obj 209 61 cnv 15 15 15 empty \$0-debug-canvas 0 4 8 0 14 -233017
+#X obj 209 61 cnv 15 15 15 empty \$0-debug-canvas 9 4 8 0 14 -233017
-1 0;
#X obj 60 61 hradio 15 1 1 10 empty empty empty 0 -6 0 8 -261689 -1
--1 0;
+-1 9;
#X obj 60 13 inlet;
#X msg 200 202 label \$1;
#X obj 200 180 makefilename %d;
@@ -478,7 +478,7 @@ IDs (it is not case sensitive):;
#X restore 10 293 pd remove instance numbers;
#X obj 9 466 route a_key b_key c_key d_key e_key f_key g_key h_key
i_key j_key k_key l_key m_key n_key o_key p_key;
-#N canvas 114 93 471 350 raw 0;
+#N canvas 114 93 475 354 raw 0;
#X obj 144 45 inlet;
#X obj 88 104 route DESKTOP;
#X obj 87 158 route DESKTOP57;
@@ -493,6 +493,7 @@ i_key j_key k_key l_key m_key n_key o_key p_key;
#X obj 290 163 print test;
#X obj 333 99 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
+#X obj 354 45 inlet;
#X connect 0 0 1 0;
#X connect 0 0 8 0;
#X connect 1 0 2 0;
@@ -503,8 +504,11 @@ i_key j_key k_key l_key m_key n_key o_key p_key;
#X connect 7 0 5 1;
#X connect 8 0 9 0;
#X connect 10 0 8 1;
+#X connect 11 0 10 0;
#X restore 408 294 pd raw;
#X floatatom 63 401 6 0 0 0 - - -;
+#X obj 455 295 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
#X connect 2 0 65 0;
#X connect 8 0 65 0;
#X connect 9 0 65 0;
@@ -560,3 +564,4 @@ i_key j_key k_key l_key m_key n_key o_key p_key;
#X connect 74 13 50 0;
#X connect 74 14 51 0;
#X connect 74 15 52 0;
+#X connect 77 0 75 1;
diff --git a/hidio.c b/hidio.c
index 0ff2cce..d2c114c 100644
--- a/hidio.c
+++ b/hidio.c
@@ -87,7 +87,6 @@ t_symbol *relative_symbols[RELATIVE_ARRAY_MAX];
//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_child_read(t_hidio *x);
//static void hidio_float(t_hidio* x, t_floatarg f);
@@ -297,40 +296,40 @@ void hidio_output_event(t_hidio *x, t_hid_element *output_data)
SETSYMBOL(event_data, output_data->name);
SETFLOAT(event_data + 1, output_data->instance);
SETFLOAT(event_data + 2, output_data->value);
-#else
+#else /* Max */
atom_setsym(event_data, output_data->name);
atom_setsym(event_data, output_data->name);
atom_setlong(event_data + 1, (long)output_data->instance);
atom_setlong(event_data + 2, (long)output_data->value);
-#endif
+#endif /* PD */
outlet_anything(x->x_data_outlet, output_data->type, 3, event_data);
}
}
/* stop polling the device */
-static void stop_poll(t_hidio* x)
+static void hidio_stop_poll(t_hidio* x)
{
- debug_print(LOG_DEBUG,"stop_poll");
+ debug_print(LOG_DEBUG,"hidio_stop_poll");
- pthread_mutex_lock(&x->x_mutex);
if (x->x_started)
{
clock_unset(x->x_clock);
debug_print(LOG_INFO,"[hidio] polling stopped");
x->x_started = 0;
}
- pthread_mutex_unlock(&x->x_mutex);
}
/*------------------------------------------------------------------------------
* METHODS FOR [hidio]'s MESSAGES
*/
-
+/* TODO: poll time should be set based on how fast the OS is actually polling
+ * the device, whether that is IOUSBEndpointDescriptor.bInterval, or something
+ * else.
+ */
void hidio_poll(t_hidio* x, t_float f)
{
- pthread_mutex_lock(&x->x_mutex);
debug_print(LOG_DEBUG,"hidio_poll");
/* if the user sets the delay less than 2, set to block size */
@@ -342,9 +341,7 @@ void hidio_poll(t_hidio* x, t_float f)
{
if(!x->x_device_open)
{
- pthread_mutex_unlock(&x->x_mutex);
hidio_open(x,ps_open,0,NULL);
- pthread_mutex_lock(&x->x_mutex);
}
if(!x->x_started)
{
@@ -353,37 +350,28 @@ void hidio_poll(t_hidio* x, t_float f)
x->x_started = 1;
}
}
- pthread_mutex_unlock(&x->x_mutex);
}
static void hidio_set_from_float(t_hidio *x, t_floatarg f)
{
- pthread_mutex_lock(&x->x_mutex);
/* 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;
- pthread_mutex_unlock(&x->x_mutex);
hidio_poll(x,f);
- pthread_mutex_lock(&x->x_mutex);
}
else if(f == 1)
{
if(! x->x_started)
{
- pthread_mutex_unlock(&x->x_mutex);
hidio_poll(x,f);
- pthread_mutex_lock(&x->x_mutex);
}
}
else if(f == 0)
{
- pthread_mutex_unlock(&x->x_mutex);
- stop_poll(x);
- pthread_mutex_lock(&x->x_mutex);
+ hidio_stop_poll(x);
}
- pthread_mutex_unlock(&x->x_mutex);
}
/* close the device */
@@ -391,10 +379,16 @@ t_int hidio_close(t_hidio *x)
{
debug_print(LOG_DEBUG,"hidio_close");
- pthread_mutex_lock(&x->x_mutex);
- x->x_requestcode = REQUEST_CLOSE;
- pthread_cond_signal(&x->x_requestcondition);
- pthread_mutex_unlock(&x->x_mutex);
+ /* just to be safe, stop it first */
+ hidio_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);
}
@@ -409,26 +403,48 @@ t_int hidio_close(t_hidio *x)
*/
static void hidio_open(t_hidio *x, t_symbol *s, int argc, t_atom *argv)
{
- short device_number;
debug_print(LOG_DEBUG,"hid_%s",s->s_name);
+ short new_device_number = get_device_number_from_arguments(argc, argv);
+ t_int started = x->x_started; // store state to restore after device is opened
- pthread_mutex_lock(&x->x_mutex);
- device_number = get_device_number_from_arguments(argc, argv);
- if (device_number > -1)
+ if (new_device_number > -1)
{
- x->x_device_number = device_number;
- x->x_requestcode = REQUEST_OPEN;
- pthread_cond_signal(&x->x_requestcondition);
+ /* check whether we have to close previous device */
+ if (x->x_device_open && new_device_number != x->x_device_number)
+ {
+ hidio_close(x);
+ }
+ /* no device open, so open one now */
+ if (!x->x_device_open)
+ {
+ if(hidio_open_device(x, new_device_number))
+ {
+ x->x_device_number = -1;
+ error("[hidio] can not open device %d",new_device_number);
+ }
+ else
+ {
+ x->x_device_open = 1;
+ x->x_device_number = new_device_number;
+ /* 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); // TODO is this useful?
+ debug_print(LOG_DEBUG,"[hidio] set device# to %d",new_device_number);
+ output_device_number(x);
+ }
+ }
}
else debug_print(LOG_WARNING,"[hidio] device does not exist");
- pthread_mutex_unlock(&x->x_mutex);
+ /* always output open result so you can test for success in Pd space */
+ output_open_status(x);
}
-/* read from event queue, called from child thread, no mutex needed */
-t_int hidio_child_read(t_hidio *x)
+static void hidio_tick(t_hidio *x)
{
-// debug_print(LOG_DEBUG,"hidio_child_read");
+// debug_print(LOG_DEBUG,"hidio_tick");
t_hid_element *current_element;
unsigned int i;
#ifdef PD
@@ -437,7 +453,9 @@ t_int hidio_child_read(t_hidio *x)
double right_now;
clock_getftime(&right_now);
#endif /* PD */
-
+
+ debug_print(LOG_DEBUG,"# %u\tnow: %u\tlast: %u", x->x_device_number,
+ right_now, last_execute_time[x->x_device_number]);
if(right_now > last_execute_time[x->x_device_number])
{
hidio_get_events(x);
@@ -455,41 +473,20 @@ t_int hidio_child_read(t_hidio *x)
current_element->previous_value = current_element->value;
}
}
-
- // TODO: why is this 1?
- return 1;
-}
-
-static void *hidio_tick(t_hidio *x)
-{
- pthread_mutex_lock(&x->x_mutex);
- if (x->x_requestcode == REQUEST_NOTHING)
- {
- x->x_requestcode = REQUEST_READ;
- pthread_cond_signal(&x->x_requestcondition);
- }
if (x->x_started)
{
clock_delay(x->x_clock, x->x_delay);
}
- pthread_mutex_unlock(&x->x_mutex);
- return NULL;
-}
-
-static void hidio_print(t_hidio *x)
-{
- pthread_mutex_lock(&x->x_mutex);
- x->x_requestcode = REQUEST_PRINT;
- pthread_cond_signal(&x->x_requestcondition);
- pthread_mutex_unlock(&x->x_mutex);
}
static void hidio_info(t_hidio *x)
{
- pthread_mutex_lock(&x->x_mutex);
- x->x_requestcode = REQUEST_INFO;
- pthread_cond_signal(&x->x_requestcondition);
- pthread_mutex_unlock(&x->x_mutex);
+ 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)
@@ -499,7 +496,7 @@ static void hidio_float(t_hidio* x, t_floatarg f)
hidio_set_from_float(x,f);
}
-#ifndef PD
+#ifndef PD /* Max */
static void hidio_int(t_hidio* x, long l)
{
debug_print(LOG_DEBUG,"hid_int");
@@ -510,185 +507,7 @@ static void hidio_int(t_hidio* x, long l)
static void hidio_debug(t_hidio *x, t_float f)
{
- pthread_mutex_lock(&x->x_mutex);
global_debug_level = f;
- pthread_mutex_unlock(&x->x_mutex);
-}
-
-
-/*------------------------------------------------------------------------------
- * child thread
- */
-
-static void *hidio_child(void *zz)
-{
- t_hidio *x = zz;
- short device_number = -1;
-
- pthread_mutex_lock(&x->x_mutex);
- while (1)
- {
- if (x->x_requestcode == REQUEST_NOTHING)
- {
- pthread_cond_signal(&x->x_answercondition);
- pthread_cond_wait(&x->x_requestcondition, &x->x_mutex);
- }
- else if (x->x_requestcode == REQUEST_OPEN)
- {
- short new_device_number = x->x_device_number;
- /* store running state to be restored after the device has been opened */
- t_int started = x->x_started;
- int ret;
- /* check whether we have to close previous device */
- if (x->x_device_open && device_number != x->x_device_number)
- {
- pthread_mutex_unlock(&x->x_mutex);
- stop_poll(x);
- ret = hidio_close_device(x);
- pthread_mutex_lock(&x->x_mutex);
- x->x_device_open = 0;
- device_number = -1;
- }
- /* no device open, so open one now */
- if (!x->x_device_open)
- {
- pthread_mutex_unlock(&x->x_mutex);
- ret = hidio_open_device(x, new_device_number);
- pthread_mutex_lock(&x->x_mutex);
- if (ret)
- {
- x->x_device_number = -1;
- error("[hidio] can not open device %d",device_number);
- }
- else
- {
- x->x_device_open = 1;
- device_number = x->x_device_number; /* keep local copy */
- pthread_mutex_unlock(&x->x_mutex);
- /* 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);
- pthread_mutex_lock(&x->x_mutex);
- }
- }
- if (x->x_requestcode == REQUEST_OPEN)
- x->x_requestcode = REQUEST_NOTHING;
- pthread_cond_signal(&x->x_answercondition);
- }
- else if (x->x_requestcode == REQUEST_READ)
- {
- pthread_mutex_unlock(&x->x_mutex);
- hidio_child_read(x);
- pthread_mutex_lock(&x->x_mutex);
- if (x->x_requestcode == REQUEST_READ)
- x->x_requestcode = REQUEST_NOTHING;
- pthread_cond_signal(&x->x_answercondition);
- }
- else if (x->x_requestcode == REQUEST_SEND)
- {
- if (x->x_requestcode == REQUEST_SEND)
- x->x_requestcode = REQUEST_NOTHING;
- pthread_cond_signal(&x->x_answercondition);
- }
- else if (x->x_requestcode == REQUEST_PRINT)
- {
- pthread_mutex_unlock(&x->x_mutex);
- hidio_doprint(x);
- pthread_mutex_lock(&x->x_mutex);
- if (x->x_requestcode == REQUEST_PRINT)
- x->x_requestcode = REQUEST_NOTHING;
- pthread_cond_signal(&x->x_answercondition);
- }
- else if (x->x_requestcode == REQUEST_INFO)
- {
- pthread_mutex_unlock(&x->x_mutex);
- 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);
- pthread_mutex_lock(&x->x_mutex);
- if (x->x_requestcode == REQUEST_INFO)
- x->x_requestcode = REQUEST_NOTHING;
- pthread_cond_signal(&x->x_answercondition);
- }
- else if (x->x_requestcode == REQUEST_CLOSE)
- {
- t_int ret;
- pthread_mutex_unlock(&x->x_mutex);
- stop_poll(x);
- ret = hidio_close_device(x);
- pthread_mutex_lock(&x->x_mutex);
- if (!ret)
- {
- debug_print(LOG_INFO,"[hidio] closed device %d",x->x_device_number);
- x->x_device_open = 0;
- }
- if (x->x_requestcode == REQUEST_CLOSE)
- x->x_requestcode = REQUEST_NOTHING;
- pthread_cond_signal(&x->x_answercondition);
- }
- else if (x->x_requestcode == REQUEST_QUIT)
- {
- pthread_mutex_unlock(&x->x_mutex);
- stop_poll(x);
- hidio_close_device(x);
- pthread_mutex_lock(&x->x_mutex);
- x->x_requestcode = REQUEST_NOTHING;
- pthread_cond_signal(&x->x_answercondition);
- break; /* leave the while loop */
- }
- else
- {
- ; /* nothing: shouldn't get here anyway */
- }
- }
- pthread_mutex_unlock(&x->x_mutex);
- return (0);
-}
-
-/* change priority of child thread */
-#ifdef PD
-static void hidio_priority(t_hidio *x, t_floatarg p)
-#else
-static void hidio_priority(t_hidio *x, long p)
-#endif
-{
- pthread_mutex_lock(&x->x_mutex);
- p = 2 * (CLIP(p, 0, 10) - 5);
- if (x->x_thread)
- {
- struct sched_param parm;
- int policy;
- if (pthread_getschedparam(x->x_thread, &policy, &parm) < 0)
- {
- post("hidio: warning: failed to get thread priority");
- }
- else
- {
- parm.sched_priority = x->x_priority + (int)p; /* adjust priority */
-
- if (parm.sched_priority < sched_get_priority_min(policy))
- {
- parm.sched_priority = sched_get_priority_min(policy);
- }
- else if (parm.sched_priority > sched_get_priority_max(policy))
- {
- parm.sched_priority = sched_get_priority_max(policy);
- }
-
- if (pthread_setschedparam(x->x_thread, policy, &parm) < 0)
- {
- post("hidio: warning: failed to change thread priority to %d", parm.sched_priority);
- }
- }
- }
- pthread_mutex_unlock(&x->x_mutex);
}
@@ -697,42 +516,13 @@ static void hidio_priority(t_hidio *x, long p)
*/
static void hidio_free(t_hidio* x)
{
- void *threadrtn;
-
debug_print(LOG_DEBUG,"hidio_free");
-
- /* stop polling for input */
- if (x->x_clock)
- clock_unset(x->x_clock);
-
- pthread_mutex_lock(&x->x_mutex);
- /* request QUIT and wait for acknowledge */
- x->x_requestcode = REQUEST_QUIT;
- if (x->x_thread)
- {
- post("hidio: stopping worker thread. . .");
- pthread_cond_signal(&x->x_requestcondition);
- while (x->x_requestcode != REQUEST_NOTHING)
- {
- post("hidio: ...signalling...");
- pthread_cond_signal(&x->x_requestcondition);
- pthread_cond_wait(&x->x_answercondition, &x->x_mutex);
- }
- pthread_mutex_unlock(&x->x_mutex);
- if (pthread_join(x->x_thread, &threadrtn))
- error("hidio_free: join failed");
- post("hidio: ...done");
- }
- else pthread_mutex_unlock(&x->x_mutex);
+ hidio_close(x);
clock_free(x->x_clock);
hidio_instance_count--;
hidio_platform_specific_free(x);
-
- pthread_cond_destroy(&x->x_requestcondition);
- pthread_cond_destroy(&x->x_answercondition);
- pthread_mutex_destroy(&x->x_mutex);
}
/* create a new instance of this class */
@@ -768,18 +558,11 @@ static void *hidio_new(t_symbol *s, int argc, t_atom *argv)
x->x_fd = INVALID_HANDLE_VALUE;
#endif /* _WIN32 */
- pthread_mutex_init(&x->x_mutex, 0);
- pthread_cond_init(&x->x_requestcondition, 0);
- pthread_cond_init(&x->x_answercondition, 0);
-
x->x_device_number = get_device_number_from_arguments(argc, argv);
x->x_instance = hidio_instance_count;
hidio_instance_count++;
- x->x_requestcode = REQUEST_NOTHING;
- pthread_create(&x->x_thread, 0, hidio_child, x);
-
return (x);
}
@@ -820,9 +603,6 @@ void hidio_setup(void)
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);
- class_addmethod(hidio_class,(t_method) hidio_priority, gensym("priority"), A_FLOAT, A_NULL);
-
-
post("[hidio] %d.%d, written by Hans-Christoph Steiner <hans@eds.org>",
HIDIO_MAJOR_VERSION, HIDIO_MINOR_VERSION);
post("\tcompiled on "__DATE__" at "__TIME__ " ");
@@ -914,7 +694,6 @@ int main()
class_addmethod(c, (method)hidio_ff_fftest, "fftest",A_DEFFLOAT,0);
class_addmethod(c, (method)hidio_ff_print, "ff_print",0);
/* perfomrance / system stuff */
- class_addmethod(c, (method)hidio_priority, "priority", A_LONG,0);
class_addmethod(c, (method)hidio_assist, "assist", A_CANT, 0);
diff --git a/hidio.h b/hidio.h
index 2e1ce08..e7d08c5 100644
--- a/hidio.h
+++ b/hidio.h
@@ -3,7 +3,6 @@
#include <stdio.h>
#ifdef _WIN32
-#include "pthread.h" /* needs pthread library */
#define LOG_DEBUG 7
#define LOG_INFO 6
#define LOG_WARNING 4
@@ -11,7 +10,6 @@
#define vsnprintf _vsnprintf
#else
#include <sys/syslog.h>
-#include <pthread.h>
#endif /* _WIN32 */
#ifdef _MSC_VER /* this only applies to Microsoft compilers */
@@ -44,7 +42,7 @@ typedef void t_clock;
#define HIDIO_MAJOR_VERSION 0
#define HIDIO_MINOR_VERSION 0
-/* static char *version = "$Revision: 1.11 $"; */
+/* static char *version = "$Revision: 1.12 $"; */
/*------------------------------------------------------------------------------
* MACRO DEFINES
@@ -67,8 +65,10 @@ typedef void t_clock;
#define MAX_ELEMENTS 64
/* this is limited so that the object doesn't cause a click getting too many
- * events from the OS's event queue */
-#define MAX_EVENTS_PER_POLL 64
+ * events from the OS's event queue. On Mac OS X, this is set in on the
+ * kernel level in HID_Utilities_External.h with the constant
+ * kDeviceQueueSize */
+#define MAX_EVENTS_PER_POLL 50
/*------------------------------------------------------------------------------
* THREADING RELATED DEFINES
@@ -93,13 +93,13 @@ typedef struct _hidio
t_object x_obj;
#ifndef PD
void *x_obex;
-#endif /* PD */
+#endif
#ifdef _WIN32
HANDLE x_fd;
-#endif /* _WIN32 */
+#endif
#ifdef __linux__
t_int x_fd;
-#endif /* __linux */
+#endif
void *x_ff_device;
short x_device_number;
short x_instance;
@@ -110,12 +110,6 @@ typedef struct _hidio
t_clock *x_clock;
t_outlet *x_data_outlet;
t_outlet *x_status_outlet;
- t_int x_requestcode;
- pthread_mutex_t x_mutex;
- pthread_cond_t x_requestcondition;
- pthread_cond_t x_answercondition;
- pthread_t x_thread;
- t_int x_priority;
} t_hidio;
@@ -186,7 +180,7 @@ extern t_int hidio_open_device(t_hidio *x, short device_number);
extern t_int hidio_close_device(t_hidio *x);
extern void hidio_build_device_list(void);
extern void hidio_get_events(t_hidio *x);
-extern void hidio_doprint(t_hidio* x); /* print info to the console */
+extern void hidio_print(t_hidio* x); /* print info to the console */
extern void hidio_platform_specific_info(t_hidio* x); /* device info on the status outlet */
extern void hidio_platform_specific_free(t_hidio *x);
extern short get_device_number_by_id(unsigned short vendor_id, unsigned short product_id);
diff --git a/hidio_darwin.c b/hidio_darwin.c
index 0905d5f..1e77731 100644
--- a/hidio_darwin.c
+++ b/hidio_darwin.c
@@ -2,8 +2,6 @@
/*
* Apple Darwin HID Manager support for Pd [hidio] object
*
- * some code from SuperCollider3's SC_HID.cpp by Jan Truetzschler Falkenstein
- *
* Copyright (c) 2004 Hans-Christoph All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -47,24 +45,29 @@
#include <IOKit/hid/IOHIDUsageTables.h>
#include <ForceFeedback/ForceFeedback.h>
+#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
+#include <mach/mach_time.h>
#include <mach/mach_error.h>
#include "hidio.h"
-#define DEBUG(x)
-//#define DEBUG(x) x
+//#define DEBUG(x)
+#define DEBUG(x) x
/*==============================================================================
* GLOBAL VARS
*======================================================================== */
-extern t_int hidio_instance_count; // in hidio.h
-
/* store device pointers so I don't have to query them all the time */
pRecDevice device_pointer[MAX_DEVICES];
+// temp hack for measuring latency
+#define LATENCY_MAX 8192
+int latency[LATENCY_MAX];
+int latency_i;
+int latency_average;
// this stuff is moving to the t_hid_element struct
@@ -136,7 +139,7 @@ static void get_usage_symbols(pRecElement pCurrentHIDElement, t_hid_element *new
case kHIDUsage_GD_Dial: convert_axis_to_symbols(pCurrentHIDElement, new_element, 7); break;
case kHIDUsage_GD_Wheel: convert_axis_to_symbols(pCurrentHIDElement, new_element, 8); break;
case kHIDUsage_GD_Hatswitch:
- // this is still a mystery how to handle
+ // TODO: this is still a mystery how to handle, due to USB HID vs. Linux input.h
new_element->type = ps_absolute;
new_element->name = absolute_symbols[9]; /* hatswitch */
break;
@@ -278,6 +281,25 @@ static t_float get_type_name_instance(t_symbol *type, t_symbol *name,
/* DARWIN-SPECIFIC SUPPORT FUNCTIONS */
/* ============================================================================== */
+double calculate_event_latency( uint64_t endTime, uint64_t startTime )
+{
+ uint64_t difference = endTime - startTime;
+ static double conversion = 0.0;
+
+ if( 0.0 == conversion )
+ {
+ mach_timebase_info_data_t info;
+ kern_return_t err = mach_timebase_info( &info );
+ if( 0 == err )
+ {
+ //convert to seconds (multiply by 1e-6 to get miliseconds)
+ conversion = 1e-6 * (double) info.numer / (double) info.denom;
+ }
+ }
+ return conversion * (double) difference;
+}
+
+
short get_device_number_by_id(unsigned short vendor_id, unsigned short product_id)
{
debug_print(LOG_DEBUG,"get_device_number_from_usage");
@@ -380,6 +402,11 @@ static void hidio_build_element_list(t_hidio *x)
HIDQueueDevice(pCurrentHIDDevice);
pCurrentHIDElement = HIDGetFirstDeviceElement( pCurrentHIDDevice,
kHIDElementTypeInput );
+
+ /* TODO: axes should be the first elements in the array since they
+ * produce many more events than buttons. This will save loop cycles
+ * in the read statement, since it had to cycle thru the elements to
+ * find a match. */
while( pCurrentHIDElement != NULL)
{
/* these two functions just get the pretty names for display */
@@ -396,33 +423,40 @@ static void hidio_build_element_list(t_hidio *x)
element_count[x->x_device_number],
element[x->x_device_number]);
- if( (pCurrentHIDElement->usagePage == kHIDPage_GenericDesktop) &&
- (!pCurrentHIDElement->relative) )
+ if(!pCurrentHIDElement->relative) /* relative elements should remain queued */
{
- switch(pCurrentHIDElement->usage)
+ switch( pCurrentHIDElement->usagePage)
{
- case kHIDUsage_GD_X:
- case kHIDUsage_GD_Y:
- case kHIDUsage_GD_Z:
- case kHIDUsage_GD_Rx:
- case kHIDUsage_GD_Ry:
- case kHIDUsage_GD_Rz:
- case kHIDUsage_GD_Slider:
- case kHIDUsage_GD_Dial:
- case kHIDUsage_GD_Wheel:
- //case kHIDUsage_GD_Hatswitch: // hatswitches are more like buttons, so queue them
- debug_print(LOG_INFO,"[hidio] storing absolute axis to poll %s, %s (0x%04x 0x%04x)",
- type_name, usage_name,
+ case kHIDPage_GenericDesktop:
+ switch(pCurrentHIDElement->usage)
+ {
+ case kHIDUsage_GD_X:
+ case kHIDUsage_GD_Y:
+ case kHIDUsage_GD_Z:
+ case kHIDUsage_GD_Rx:
+ case kHIDUsage_GD_Ry:
+ case kHIDUsage_GD_Rz:
+ case kHIDUsage_GD_Slider:
+ case kHIDUsage_GD_Dial:
+ case kHIDUsage_GD_Wheel:
+ //case kHIDUsage_GD_Hatswitch: // hatswitches are more like buttons, so queue them
+ debug_print(LOG_INFO,"[hidio] storing absolute axis to poll %s, %s (0x%04x 0x%04x)",
+ type_name, usage_name,
+ pCurrentHIDElement->usagePage, pCurrentHIDElement->usage);
+ if(HIDDequeueElement(pCurrentHIDDevice,pCurrentHIDElement) != kIOReturnSuccess)
+ debug_print(LOG_ERR,"[hidio] could not dequeue element");
+ new_element->polled = 1;
+ break;
+ }
+ default:
+ debug_print(LOG_INFO,"\tqueuing element %s, %s (0x%04x 0x%04x)",
+ type_name, usage_name,
pCurrentHIDElement->usagePage, pCurrentHIDElement->usage);
- if(HIDDequeueElement(pCurrentHIDDevice,pCurrentHIDElement) != kIOReturnSuccess)
- debug_print(LOG_ERR,"[hidio] could not dequeue element");
- new_element->polled = 1;
- break;
}
}
- else
+ else
{
- debug_print(LOG_INFO,"[hidio] queuing element %s, %s (0x%04x 0x%04x)",
+ debug_print(LOG_INFO,"\tqueuing element %s, %s (0x%04x 0x%04x)",
type_name, usage_name,
pCurrentHIDElement->usagePage, pCurrentHIDElement->usage);
}
@@ -608,15 +642,16 @@ void hidio_platform_specific_info(t_hidio *x)
void hidio_get_events(t_hidio *x)
{
- unsigned int i;
- pRecDevice pCurrentHIDDevice;
- t_hid_element *current_element;
- IOHIDEventStruct event;
+ unsigned int i,j;
+ pRecDevice pCurrentHIDDevice;
+ t_hid_element *current_element;
+ IOHIDEventStruct event;
+ uint64_t timestamp, now, difference;
pCurrentHIDDevice = device_pointer[x->x_device_number];
/* get the queued events first and store them */
-// while( (HIDGetEvent(pCurrentHIDDevice, (void*) &event)) && (event_counter < MAX_EVENTS_PER_POLL) )
+// TODO: while( (HIDGetEvent(pCurrentHIDDevice, (void*) &event)) && (event_counter < MAX_EVENTS_PER_POLL) )
while(HIDGetEvent(pCurrentHIDDevice, (void*) &event))
{
i=0;
@@ -628,9 +663,35 @@ void hidio_get_events(t_hidio *x)
(IOHIDElementCookie) event.elementCookie) );
current_element->value = event.value;
- debug_print(LOG_DEBUG,"output this: %s %s %d prev %d",current_element->type->s_name,
- current_element->name->s_name, current_element->value,
- current_element->previous_value);
+// debug_print(LOG_DEBUG,"output this: %s %s %d prev %d",current_element->type->s_name,
+// current_element->name->s_name, current_element->value,
+// current_element->previous_value);
+// debug_print(LOG_DEBUG,"timestamp: %u %u", event.timestamp.hi, event.timestamp.lo);
+ timestamp = * (uint64_t *) &(event.timestamp);
+ now = mach_absolute_time();
+ difference = calculate_event_latency(now, timestamp);
+ // temp hack to measure latency
+ if( latency_i < LATENCY_MAX)
+ {
+ latency[latency_i] = (int) difference;
+ if( latency[latency_i] < 100 )
+ latency_average += latency[latency_i];
+ ++latency_i;
+ }
+ else
+ {
+/* for(j=0;j<LATENCY_MAX;++j)
+ {
+ fprintf(stderr,"%d ",latency[j]);
+ }*/
+ latency_average = latency_average / LATENCY_MAX;
+ fprintf(stderr,"average: %d\n",latency_average);
+ latency_i = 0;
+ latency_average = 0;
+ }
+// debug_print(LOG_DEBUG,"\t\t\t\t\ttimestamp: %llu",timestamp);
+// debug_print(LOG_DEBUG,"\t\t\t\t\tdifference: %llu", difference);
+// post("%d %llu", i, difference);
}
/* absolute axes don't need to be queued, they can just be polled */
for(i=0; i< element_count[x->x_device_number]; ++i)
@@ -645,7 +706,7 @@ void hidio_get_events(t_hidio *x)
}
}
-
+// TODO: return the same as POSIX open()/close() - 0=success, -1=fail
t_int hidio_open_device(t_hidio *x, short device_number)
{
debug_print(LOG_DEBUG,"hidio_open_device");
@@ -656,6 +717,8 @@ t_int hidio_open_device(t_hidio *x, short device_number)
io_service_t hidDevice = 0;
FFDeviceObjectReference ffDeviceReference = NULL;
+ latency_i = 0;latency_average = 0; // temp hack, to be removed
+
/* rebuild device list to make sure the list is current */
if( !HIDHaveDeviceList() ) hidio_build_device_list();
@@ -694,7 +757,7 @@ t_int hidio_open_device(t_hidio *x, short device_number)
return(result);
}
-
+// TODO: return the same as POSIX open()/close() - 0=success, -1=fail
t_int hidio_close_device(t_hidio *x)
{
debug_print(LOG_DEBUG,"hidio_close_device");
@@ -738,7 +801,7 @@ void hidio_build_device_list(void)
}
/* TODO: this should be dumped for [devices( and [elements( messages */
-void hidio_doprint(t_hidio *x)
+void hidio_print(t_hidio *x)
{
if( !HIDHaveDeviceList() ) hidio_build_device_list();
hidio_print_device_list(x);
@@ -752,6 +815,7 @@ void hidio_doprint(t_hidio *x)
void hidio_platform_specific_free(t_hidio *x)
{
+ int j;
debug_print(LOG_DEBUG,"hidio_platform_specific_free");
/* only call this if the last instance is being freed */
if (hidio_instance_count < 1)
@@ -760,6 +824,10 @@ void hidio_platform_specific_free(t_hidio *x)
HIDReleaseAllDeviceQueues();
HIDReleaseDeviceList();
}
+ for(j=0;j<LATENCY_MAX;++j)
+ {
+ fprintf(stderr,"%d ",latency[j]);
+ }
}
diff --git a/hidio_linux.c b/hidio_linux.c
index 7da4ff9..d352aea 100644
--- a/hidio_linux.c
+++ b/hidio_linux.c
@@ -434,7 +434,7 @@ void hidio_print(t_hidio* x)
hidio_print_element_list(x);
}
-
+// TODO: return the same as POSIX open()/close() - 0=success, -1=fail
t_int hidio_open_device(t_hidio *x, short device_number)
{
debug_print(LOG_DEBUG,"hidio_open_device");
@@ -477,9 +477,8 @@ t_int hidio_open_device(t_hidio *x, short device_number)
return (0);
}
-/*
- * Under GNU/Linux, the device is a filehandle
- */
+/* Under GNU/Linux, the device is a filehandle */
+// TODO: return the same as POSIX open()/close() - 0=success, -1=fail
t_int hidio_close_device(t_hidio *x)
{
debug_print(LOG_DEBUG,"hidio_close_device");
diff --git a/test/latency_test.pd b/test/latency_test.pd
new file mode 100644
index 0000000..468c7b6
--- /dev/null
+++ b/test/latency_test.pd
@@ -0,0 +1,22 @@
+#N canvas 0 22 474 324 10;
+#X msg 111 33 open 2;
+#X msg 194 18 poll 1;
+#X msg 52 88 info;
+#X obj 208 181 route poll;
+#X floatatom 209 206 5 0 0 0 - - -;
+#X msg 302 108 0;
+#X msg 205 65 poll 5;
+#X msg 206 89 poll 10;
+#X msg 201 41 poll 3;
+#X msg 210 111 poll 25;
+#X obj 175 153 hidio 2;
+#X connect 0 0 10 0;
+#X connect 1 0 10 0;
+#X connect 2 0 10 0;
+#X connect 3 0 4 0;
+#X connect 5 0 10 0;
+#X connect 6 0 10 0;
+#X connect 7 0 10 0;
+#X connect 8 0 10 0;
+#X connect 9 0 10 0;
+#X connect 10 1 3 0;
diff --git a/test/test_instance.pd b/test/test_instance.pd
new file mode 100644
index 0000000..2605661
--- /dev/null
+++ b/test/test_instance.pd
@@ -0,0 +1,93 @@
+#N canvas 560 22 506 400 10;
+#X obj 251 334 textfile;
+#X obj 330 286 prepend add;
+#X msg 251 186 clear;
+#X msg 103 220 write \$1;
+#X obj 221 32 receive test_control;
+#X obj 28 125 route write clear;
+#X msg 400 185 open 0;
+#X msg 349 186 close;
+#X obj 349 242 prepend set;
+#X msg 350 262 key key_227 0;
+#X obj 26 187 makefilename /tmp/hid-%d.txt;
+#X msg 28 149 bang;
+#X obj 27 168 float \$0;
+#X symbolatom 26 247 0 0 0 0 - - -;
+#X obj 221 53 route float;
+#X obj 221 93 trigger float float;
+#X obj 349 114 select 0;
+#X obj 400 136 bang;
+#X obj 259 206 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 4 22 552 367 subpatch 1;
+#X obj 264 314 textfile;
+#X obj 343 266 prepend add;
+#X msg 264 166 clear;
+#X msg 106 199 write \$1;
+#X obj 234 12 receive test_control;
+#X obj 31 104 route write clear;
+#X msg 413 165 open 0;
+#X msg 362 166 close;
+#X obj 362 222 prepend set;
+#X msg 363 242 key key_227 0;
+#X msg 31 128 bang;
+#X obj 30 147 float \$0;
+#X symbolatom 29 226 0 0 0 0 - - -;
+#X obj 234 33 route float;
+#X obj 234 73 trigger float float;
+#X obj 362 94 select 0;
+#X obj 413 116 bang;
+#X obj 272 186 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 29 166 makefilename /tmp/hid-%d-sub.txt;
+#X obj 343 194 hidio 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 2 0 17 0;
+#X connect 3 0 0 0;
+#X connect 4 0 13 0;
+#X connect 5 0 10 0;
+#X connect 5 1 2 0;
+#X connect 6 0 19 0;
+#X connect 7 0 19 0;
+#X connect 8 0 9 0;
+#X connect 10 0 11 0;
+#X connect 11 0 18 0;
+#X connect 13 0 14 0;
+#X connect 13 1 5 0;
+#X connect 14 0 19 0;
+#X connect 14 1 15 0;
+#X connect 15 0 7 0;
+#X connect 15 1 16 0;
+#X connect 16 0 2 0;
+#X connect 16 0 6 0;
+#X connect 18 0 12 0;
+#X connect 18 0 3 0;
+#X connect 19 0 1 0;
+#X connect 19 0 8 0;
+#X restore 40 32 pd subpatch test;
+#X obj 330 214 hidio 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 2 0 18 0;
+#X connect 3 0 0 0;
+#X connect 4 0 14 0;
+#X connect 5 0 11 0;
+#X connect 5 1 2 0;
+#X connect 6 0 20 0;
+#X connect 7 0 20 0;
+#X connect 8 0 9 0;
+#X connect 10 0 13 0;
+#X connect 10 0 3 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 14 0 15 0;
+#X connect 14 1 5 0;
+#X connect 15 0 20 0;
+#X connect 15 1 16 0;
+#X connect 16 0 7 0;
+#X connect 16 1 17 0;
+#X connect 17 0 2 0;
+#X connect 17 0 6 0;
+#X connect 20 0 1 0;
+#X connect 20 0 8 0;
diff --git a/test/test_instance_GUI.pd b/test/test_instance_GUI.pd
new file mode 100644
index 0000000..f5bb96c
--- /dev/null
+++ b/test/test_instance_GUI.pd
@@ -0,0 +1,26 @@
+#N canvas 115 434 475 227 10;
+#X obj 96 93 send test_control;
+#X obj 156 25 tgl 35 1 empty empty empty 0 -6 0 8 -24198 -1 -1 0 1
+;
+#X msg 89 44 clear;
+#X msg 38 44 write;
+#X msg 273 166 \; pd open \$1 \$2;
+#X obj 394 119 getdir;
+#X obj 273 119 symbol;
+#X msg 273 69 test_instance.pd;
+#X obj 273 95 trigger anything bang;
+#X obj 273 138 pack symbol symbol;
+#X obj 275 43 until;
+#X msg 275 20 4;
+#X msg 32 166 \; pd-test_instance.pd menuclose;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 5 0 9 1;
+#X connect 6 0 9 0;
+#X connect 7 0 8 0;
+#X connect 8 0 6 0;
+#X connect 8 1 5 0;
+#X connect 9 0 4 0;
+#X connect 10 0 7 0;
+#X connect 11 0 10 0;