aboutsummaryrefslogtreecommitdiff
path: root/multio
diff options
context:
space:
mode:
Diffstat (limited to 'multio')
-rwxr-xr-xmultio/Makefile67
-rwxr-xr-xmultio/help-multio.pd95
-rwxr-xr-xmultio/multio.c605
3 files changed, 767 insertions, 0 deletions
diff --git a/multio/Makefile b/multio/Makefile
new file mode 100755
index 0000000..9f79bae
--- /dev/null
+++ b/multio/Makefile
@@ -0,0 +1,67 @@
+NAME=multio
+CSYM=multio
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).dll
+
+.SUFFIXES: .dll
+
+VC="C:\Programmi\Microsoft Visual Studio .NET\Vc7"
+PDPATH="H:\PureData\pd-0.38-3.msw\pd"
+LIBUSBPATH="H:\PureData\multIO\libusb-win32-device-bin-0.1.10.1"
+PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
+
+
+PDNTINCLUDE = /I. (PDPATH)\tcl\include /I$(PDPATH)\src /I$(VC)\include /I$(LIBUSBPATH)\include
+
+PDNTLDIR = $(VC)\lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.lib \
+ $(LIBUSBPATH)\lib\msvc\libusb.lib \
+ $(PDPATH)\bin\pd.lib \
+ $(PDPATH)\bin\pthreadVC.lib
+
+.c.dll:
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+ link /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB)
+
+# ----------------------- LINUX i386 -----------------------
+
+pd_linux: $(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -fPIC \
+ -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch $(CFLAGS)
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm -lusb
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: $(NAME).pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.pd_darwin:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o
+
+# ----------------------------------------------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/multio/help-multio.pd b/multio/help-multio.pd
new file mode 100755
index 0000000..eaae25b
--- /dev/null
+++ b/multio/help-multio.pd
@@ -0,0 +1,95 @@
+#N canvas 112 95 1011 631 12;
+#X obj 132 124 tgl 30 0 empty empty empty 0 -6 0 8 -62784 -1 -1 0 1
+;
+#X obj 506 210 unpack f f;
+#X floatatom 421 247 5 0 0 0 - - -;
+#X floatatom 499 248 5 0 0 0 - - -;
+#X msg 132 161 open;
+#X obj 132 202 multio;
+#X msg 132 69 readout_time 20;
+#X msg 132 98 readout_time 1000;
+#X msg 132 25 readout_time 1;
+#X text 185 163 <-- open the device (opened by default if possible)
+;
+#X text 170 132 <-- start/stop readout of the device (on by default)
+;
+#X text 290 39 <--+ | <--+-> set the time between readouts (msec) |
+20 msec is the default <--+;
+#X obj 123 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 59 1;
+#X obj 154 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 198 1;
+#X obj 185 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 177 1;
+#X obj 216 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 155 1;
+#X obj 247 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 3 1;
+#X obj 278 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 0 1;
+#X obj 309 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 186 1;
+#X obj 340 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 769 1;
+#X obj 371 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 353 1;
+#X obj 402 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 1659 1;
+#X obj 433 357 vsl 30 128 0 4096 0 0 empty empty empty 0 -8 0 8 -128992
+-1 -1 1380 1;
+#X obj 123 274 route 0 1 2 3 4 5 6 7 8 9 10;
+#X obj 433 311 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 445 256;
+#X obj 402 330 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 535 256;
+#X obj 371 311 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 114 256;
+#X obj 340 330 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 248 256;
+#X obj 309 311 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 60 256;
+#X obj 278 330 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 0 256;
+#X obj 247 311 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 1 256;
+#X obj 216 330 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 50 256;
+#X obj 185 311 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 57 256;
+#X obj 154 330 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 64 256;
+#X obj 123 311 nbx 4 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0
+14 -262144 -1 -1 19 256;
+#X msg 130 46 readout_time 5;
+#X connect 0 0 5 0;
+#X connect 1 0 2 0;
+#X connect 1 1 3 0;
+#X connect 4 0 5 0;
+#X connect 5 0 23 0;
+#X connect 5 1 1 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 0;
+#X connect 23 0 34 0;
+#X connect 23 1 33 0;
+#X connect 23 2 32 0;
+#X connect 23 3 31 0;
+#X connect 23 4 30 0;
+#X connect 23 5 29 0;
+#X connect 23 6 28 0;
+#X connect 23 7 27 0;
+#X connect 23 8 26 0;
+#X connect 23 9 25 0;
+#X connect 23 10 24 0;
+#X connect 24 0 22 0;
+#X connect 25 0 21 0;
+#X connect 26 0 20 0;
+#X connect 27 0 19 0;
+#X connect 28 0 18 0;
+#X connect 29 0 17 0;
+#X connect 30 0 16 0;
+#X connect 31 0 15 0;
+#X connect 32 0 14 0;
+#X connect 33 0 13 0;
+#X connect 34 0 12 0;
+#X connect 35 0 5 0;
diff --git a/multio/multio.c b/multio/multio.c
new file mode 100755
index 0000000..65c1ac5
--- /dev/null
+++ b/multio/multio.c
@@ -0,0 +1,605 @@
+/*
+multio
+
+connects to multIO and listens..
+left outlet for analog
+middle for digital
+
+output is a list of 2 floats (channel, value)
+
+
+*/
+#ifdef NT
+#include <windows.h>
+#endif
+
+#include "m_pd.h"
+#include "usb.h"
+#include "pthread.h"
+
+
+#define DEFDELTIME 20 // time between readouts in msec
+#define TIMEOUT 1000 // timeout time in usb interrupts reading and writing
+#define MAXBUF 1024
+
+/* PICkit USB values */
+static const int multio_vendorID=0xdead; // Microchip, Inc
+static const int multio_productID=0xbeef; // PICkit 1 FLASH starter kit
+static const int multio_configuration=2; /* 1: HID; 2: vendor specific */
+static const int multio_interface=0;
+static const int reqLen=8;
+static char is_open;
+typedef unsigned char byte;
+
+static t_class *multio_class;
+
+typedef struct _multio
+{
+ t_object x_obj; // myself
+ usb_dev_handle *d; // handle to multIO
+ t_clock *x_clock; // as in metro
+ double x_deltime; // as in metro
+ int x_hit; // as in metro
+ pthread_attr_t multio_thread_attr;
+ pthread_t x_threadid;
+ unsigned char double_buffer[2][MAXBUF]; // a double buffer: thread writes one, cyclic read of the other one
+ // the second parameter should be deafult 1000 but setable via
+ // object parameters
+ int buf_count[2]; // how many bytes are in a buffer
+ unsigned char whichbuf; // which one to read from
+ char old_digi[8]; // buffer of digital input, is a byte, 8 values at a time
+ char digi_outs[8]; // buffer of digital input, is a byte, 8 values at a time
+ int analog_buffer[64]; // buffered analog outs
+ t_outlet *a_out, *d_out, *s_out; // outlets
+} t_multio;
+
+static void *usb_read_thread(void *w)
+{
+ t_multio *x = (t_multio*) w;
+ int cnt = 0;
+ int bytesread = 0;
+ unsigned char mybuf = 1;
+ unsigned char buffer[8];
+ while(1) // never ending
+ {
+ pthread_testcancel();
+ if(x->d) // only read if the device is opened
+ {
+ if(x->buf_count[x->whichbuf] <= 0) // check if the read buffer is empty
+ {
+ mybuf = x->whichbuf; // if so, use it for writing
+ x->whichbuf = !(x->whichbuf &1); // and toggle the read buffer
+ }
+ bytesread = usb_interrupt_read(x->d, 0x81, buffer, 8, 1000);
+ if(bytesread > 0)
+ {
+ if(x->buf_count[mybuf]+bytesread > MAXBUF)
+ x->buf_count[mybuf] = 0;
+ x->double_buffer[mybuf][x->buf_count[mybuf]++] = bytesread; // store the number of bytes for that message
+ for(cnt = 0; cnt < bytesread; cnt++) // append the message data into the buffer
+ {
+ x->double_buffer[mybuf][x->buf_count[mybuf]++] = buffer[cnt];
+ }
+// post("thread read %i bytes to buffer %i (now %i bytes)",bytesread, mybuf,x->buf_count[mybuf] );
+ }
+ }
+#ifdef NT
+ Sleep(1);
+#endif
+ }
+}
+
+static void start_thread(t_multio *x)
+{
+
+// create the worker thread
+ if(pthread_attr_init(&x->multio_thread_attr) < 0)
+ {
+ post("multio: could not launch receive thread");
+ return;
+ }
+ if(pthread_attr_setdetachstate(&x->multio_thread_attr, PTHREAD_CREATE_DETACHED) < 0)
+ {
+ post("multio: could not launch receive thread");
+ return;
+ }
+ if(pthread_create(&x->x_threadid, &x->multio_thread_attr, usb_read_thread, x) < 0)
+ {
+ post("multio: could not launch receive thread");
+ return;
+ }
+ else
+ {
+ post("multio: thread %d launched", (int)x->x_threadid );
+ }
+}
+
+// methods invoked by the inlets
+static void multio_analog_write(t_multio *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int channel;
+ int value;
+ unsigned char buffer[8];
+ int bytesread;
+
+ if (argc<2)
+ {
+ error("multio: multio_analog_write error: i need minimum 2 values list");
+ return;
+ }
+
+ if (!(x->d))
+ {
+ error("multio: multI/O not initialized");
+ return;
+ }
+
+ channel = atom_getfloat(argv++);
+ value = atom_getfloat(argv);
+
+ if(channel < 0 || channel > 63)
+ {
+ error("multio: inconsistent dac output channel");
+ return;
+ }
+
+ if (value != x->analog_buffer[channel])
+ {
+ x->analog_buffer[channel] = value;
+ buffer[0] = 97 + channel; // channel is 0 based
+ buffer[1] = value & 0xff;
+ buffer[2] = (value & 0xff00) >> 8;
+ bytesread = usb_interrupt_write(x->d, 1, buffer, 3, TIMEOUT);
+ }
+}
+
+
+static void multio_digi_write(t_multio *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int channel;
+ int value;
+ unsigned char buffer[8];
+ int bytesread;
+ char testbit = 0x01;
+ int count;
+ int group;
+ int channel_in_group;
+ char ctmp;
+ char bitmask;
+
+ if (argc<2)
+ {
+ error("multio: multio_digi_write error: i need minimum 2 values list");
+ return;
+ }
+ channel = atom_getfloat(argv++);
+ value = atom_getfloat(argv);
+
+ if(channel < 0 || channel > 63)
+ {
+ error("multio: inconsistent digital output channel");
+ return;
+ }
+
+ group = channel / 8 ;
+ channel_in_group = channel % 8;
+
+ bitmask = 0x01 << channel_in_group;
+ ctmp = x->digi_outs[group] & ~bitmask;
+ if (value)
+ ctmp = ctmp | bitmask;
+ if(ctmp != x->digi_outs[group])
+ {
+ x->digi_outs[group] = ctmp;
+ buffer[0] = group + 1; // + 1 is the offset for digi outs (1..9)
+ buffer[1] = ctmp;
+ bytesread = usb_interrupt_write(x->d, 1, buffer, 3, TIMEOUT);
+ post("multio: writing %i to group %i", ctmp, group);
+ }
+
+}
+
+static void multio_system_write(t_multio *x, t_symbol *s, int argc, t_atom *argv)
+{
+
+ unsigned char cmd, bvalue, smallvalue;
+ unsigned short int value;
+ unsigned char buffer[5];
+
+ if (argc<3)
+ {
+ error("multio: multio_system_write error: i need minimum 3 values list");
+ return;
+ }
+ cmd = atom_getfloat(argv++);
+ bvalue = atom_getfloat(argv++);
+
+ buffer[0] = 161;
+ buffer[1] = cmd;
+ buffer[2] = bvalue;
+
+ switch(cmd)
+ {
+ case 0:
+ case 1: usb_interrupt_write(x->d, 1, buffer, 3, TIMEOUT); break;
+ case 2:
+ case 3:
+ case 4: value = atom_getfloat(argv);
+ buffer[3] = value & 0x00ff;
+ buffer[4] = value >> 8;
+ usb_interrupt_write(x->d, 1, buffer, 5, TIMEOUT);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8: buffer[3] = atom_getfloat(argv);
+ usb_interrupt_write(x->d, 1, buffer, 4, TIMEOUT);
+ break;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17: usb_interrupt_write(x->d, 1, buffer, 3, TIMEOUT); break;
+ default: error("multio: unknown system command"); break;
+ }
+}
+
+// read & process the buffer
+// this will be called each tick in the pd object
+static void process_buffer(t_multio *x)
+{
+ int cnt;
+ if(x->buf_count[x->whichbuf] > 0)
+ {
+// post("process %i bytes buffer\n", x->buf_count[x->whichbuf]);
+ for(cnt = 0; cnt < x->buf_count[x->whichbuf]; cnt++)
+ {
+ if(x->double_buffer[x->whichbuf][cnt] == 2)
+ {
+// post("process buf: %i msglen: %i id: %i val: %i", x->whichbuf, x->double_buffer[x->whichbuf][cnt],x->double_buffer[x->whichbuf][cnt+1],x->double_buffer[x->whichbuf][cnt+2]);
+ if (x->double_buffer[x->whichbuf][cnt+1]>=1 && x->double_buffer[x->whichbuf][cnt+1] <= 8)
+ {
+ // digital input
+ //send_digi(x, first-1, buffer[1]);
+ char testbit = 0x01;
+ t_atom lista[2];
+ int count;
+ int group = x->double_buffer[x->whichbuf][cnt+1]-1;
+
+ for(count = 0; count < 8; count++)
+ {
+ if((x->double_buffer[x->whichbuf][cnt+2] & testbit) != (x->old_digi[group] & testbit))
+ {
+ SETFLOAT(lista, (group*8)+count);
+ if(x->double_buffer[x->whichbuf][cnt+2] & testbit)
+ SETFLOAT(lista+1, 1);
+ else
+ SETFLOAT(lista+1, 0);
+ outlet_anything(x->d_out, gensym("list") , 2, lista);
+ }
+ testbit <<= 1;
+ }
+ x->old_digi[group] = x->double_buffer[x->whichbuf][cnt+2];
+ }
+ cnt += 2;
+ }
+ else if(x->double_buffer[x->whichbuf][cnt] == 3)
+ {
+// post("process buf: %i msglen: %i id: %i val: %i", x->whichbuf, x->double_buffer[x->whichbuf][cnt],x->double_buffer[x->whichbuf][cnt+1],x->double_buffer[x->whichbuf][cnt+2] + (x->double_buffer[x->whichbuf][cnt+3] << 8));
+ if (x->double_buffer[x->whichbuf][cnt+1]>=9 && x->double_buffer[x->whichbuf][cnt+1] <=96)
+ {
+ // analog input
+ t_atom lista[2];
+ int result;
+ int channel = x->double_buffer[x->whichbuf][cnt+1]-9;
+
+ result = x->double_buffer[x->whichbuf][cnt+2] + (x->double_buffer[x->whichbuf][cnt+3] << 8);
+ x->analog_buffer[channel] = result;
+
+ SETFLOAT(lista, channel);
+ SETFLOAT(lista+1, result);
+ outlet_anything(x->a_out, gensym("list"),2 , lista);
+ }
+ cnt += 3;
+ }
+ else
+ cnt += x->double_buffer[x->whichbuf][cnt];
+ }
+ x->buf_count[x->whichbuf] = 0;
+ }
+}
+
+/*
+// method invoked by the timer
+static void multio_read(t_multio *x)
+{
+ unsigned char buffer[8];
+ int first;
+ int bytesread;
+ byte retData[8];
+ int reads=64;
+
+ if (x->d)
+ {
+ } else
+ {
+ post("error, connection not inizialized");
+ return;
+ }
+
+ while(usb_interrupt_read(x->d, 0x81, buffer, 8, 2) > 0)
+
+ {
+// reads--;
+//if (usb_interrupt_read(x->d, 0x81, buffer, 8, TIMEOUT) > 0)
+//{
+ first = buffer[0];
+
+ if (first>=1 && first <= 8)
+ {
+ // digital input
+ //send_digi(x, first-1, buffer[1]);
+ char testbit = 0x01;
+ t_atom lista[2];
+ int count;
+ int group = first-1;
+
+ for(count = 0; count < 8; count++)
+ {
+ if((buffer[1] & testbit) != (x->old_digi[group] & testbit))
+ {
+ SETFLOAT(lista, (group*8)+count);
+ if(buffer[1] & testbit)
+ SETFLOAT(lista+1, 1);
+ else
+ SETFLOAT(lista+1, 0);
+ outlet_anything(x->d_out, gensym("list") , 2, lista);
+ }
+ testbit <<= 1;
+ }
+ x->old_digi[group] = buffer[1];
+ }
+
+ if (first>=9 && first <=96)
+ {
+ // analog input
+ t_atom lista[2];
+ int result;
+ int channel = first-9;
+
+ result = buffer[1] + (buffer[2] << 8);
+ x->analog_buffer[channel] = result;
+
+ SETFLOAT(lista, channel);
+ SETFLOAT(lista+1, result);
+ outlet_anything(x->a_out, gensym("list"),2 , lista);
+ }
+
+ if (first==161)
+ {
+ t_atom list2[2];
+ t_atom list3[3];
+
+ switch(buffer[1])
+ {
+ case 0:
+ case 1: SETFLOAT(list2, buffer[1]);
+ SETFLOAT(list2+1, buffer[2]);
+ outlet_anything(x->s_out, gensym("list"),2 , list2);
+ break;
+ case 2:
+ case 3:
+ case 4: SETFLOAT(list3, buffer[1]);
+ SETFLOAT(list3+1, buffer[2]);
+ SETFLOAT(list3+2, (float)(buffer[3] + (buffer[4]<<8)) );
+ outlet_anything(x->s_out, gensym("list"),3 , list3);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8: SETFLOAT(list3, buffer[1]);
+ SETFLOAT(list3+1, buffer[2]);
+ SETFLOAT(list3+2, buffer[3]);
+ outlet_anything(x->s_out, gensym("list"),3 , list3);
+ break;
+ case 9: SETFLOAT(list2, buffer[1] - 9);
+ outlet_anything(x->a_out, gensym("list"),2 , list2);
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17: SETFLOAT(list3, buffer[1]);
+ SETFLOAT(list3+1, buffer[2]);
+ SETFLOAT(list3+2, buffer[3]);
+ outlet_anything(x->s_out, gensym("list"),3 , list3);
+ break;
+ default: error("unknown system command echo"); break;
+ }
+ // system input
+ }
+ }
+}
+*/
+
+static void multio_open(t_multio *x)
+{
+ struct usb_device *device;
+ struct usb_bus* bus;
+ unsigned char buffer[8];
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+
+ for (bus=usb_get_busses();bus!=NULL;bus=bus->next)
+ {
+ struct usb_device* usb_devices = bus->devices;
+
+
+ for(device=usb_devices;device;device=device->next)
+ {
+
+ if (device->descriptor.idVendor == multio_vendorID
+ &&device->descriptor.idProduct == multio_productID)
+ {
+
+ post( "multio: Found mamalala multI/O as device '%s' on USB bus %s",
+ device->filename,
+ device->bus->dirname);
+ x->d=usb_open(device);
+
+ if (x->d)
+ { /* This is our device-- claim it */
+
+ if (usb_set_configuration(x->d,multio_configuration)) {
+ post("multio: Error setting USB configuration.");
+ usb_close(x->d);
+ return;
+ }
+ else post("multio: Selecting non-HID config");
+
+
+ if (usb_claim_interface(x->d,multio_interface)) {
+ post("multio: Claim failed-- the mamalala multI/O is in use by another driver.\n"
+ "multio: Do a `dmesg` to see which kernel driver has claimed it--\n"
+ "multio: You may need to `rmmod hid` or patch your kernel's hid driver.");
+ usb_close(x->d);
+ return;
+
+ }
+ else post("multio: Claimed interface");
+ while(usb_interrupt_read(x->d, 0x81, buffer, 8, 10) > 0)
+ {
+
+ }
+ return;
+ }
+ }
+ }
+ }
+ // if i am here then i couldn't find mutlIO!
+ post("multio: unable to find multI/O !");
+}
+
+
+
+
+static void multio_tick(t_multio *x)
+{
+ x->x_hit = 0;
+// multio_read(x);
+process_buffer(x);
+ if (!x->x_hit) clock_delay(x->x_clock, x->x_deltime);
+}
+
+static void multio_float(t_multio *x, t_float f)
+{
+ if (f != 0) multio_tick(x);
+ else clock_unset(x->x_clock);
+ x->x_hit = 1;
+}
+
+static void multio_start(t_multio *x)
+{
+ multio_float(x, 1);
+}
+
+static void multio_stop(t_multio *x)
+{
+ multio_float(x, 0);
+}
+
+static void multio_ft1(t_multio *x, t_floatarg g)
+{
+ if (g < 1) g = 1;
+ x->x_deltime = g;
+}
+
+
+
+static void multio_free(t_multio *x)
+{
+if(is_open)
+{
+ clock_free(x->x_clock);
+ if(x->d)
+ {
+ while(pthread_cancel(x->x_threadid) < 0)
+ post("multio: killing thread\n");
+ post("multio: thread canceled\n");
+ usb_close(x->d);
+ }
+ is_open = 0;
+}
+else
+post("multio: not active object");
+}
+
+
+static void *multio_new(t_symbol *s, int argc, t_atom *argv)
+{
+if(!is_open)
+{
+ t_multio *x = (t_multio *)pd_new(multio_class);
+ x->x_clock = clock_new(x, (t_method)multio_tick);
+ x->x_deltime = DEFDELTIME;
+ x->a_out = outlet_new(&x->x_obj, &s_list);
+ x->d_out = outlet_new(&x->x_obj, &s_list);
+ x->s_out = outlet_new(&x->x_obj, &s_list);
+ // look for multIO
+
+ multio_open(x);
+ if(x->d)
+ start_thread(x);
+ // inlets for digital and system
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("list"), gensym("digi_write")); // remap to digi_write
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("list"), gensym("system_write"));
+ is_open = 1;
+ multio_start(x);
+ return (x);
+}
+else
+{
+post("multio: object already exists");
+return(0);
+}
+}
+
+void multio_setup(void)
+{
+ multio_class = class_new(gensym("multio"), (t_newmethod)multio_new,
+ (t_method)multio_free, sizeof(t_multio), CLASS_DEFAULT, A_GIMME, 0);
+ //class_addbang(multio_class, (t_method)multio_bang);
+ // to set the time between 2 readouts
+ class_addmethod(multio_class, (t_method)multio_ft1, gensym("readout_time"),
+ A_FLOAT, 0);
+ class_addfloat(multio_class, (t_method)multio_float); // start/stop using a toggle
+ // to stop reading
+ class_addmethod(multio_class, (t_method)multio_stop, gensym("stop"), 0);
+ // to start reading
+ class_addmethod(multio_class, (t_method)multio_start, gensym("start"), 0);
+ // open the device
+ class_addmethod(multio_class, (t_method)multio_open, gensym("open"), 0);
+ // write analog data using leftmost inlet
+ class_addlist(multio_class, (t_method)multio_analog_write);
+ class_addmethod(multio_class, (t_method)multio_digi_write, gensym("digi_write"),
+ A_GIMME, 0);
+ class_addmethod(multio_class, (t_method)multio_system_write, gensym("system_write"),
+ A_GIMME, 0);
+is_open = 0;
+ // welcome message
+ post("\nmultio: a pd driver for the multI/O USB device");
+ post("multio: www.davidemorelli.it - multio.mamalala.de");
+
+
+}
+
+