From 2e3417388d79966bed87965155b3f5f485728a4a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 17 May 2007 05:33:45 +0000 Subject: merged in b6 and got it compiling, lots of warning, I would be surprised if it actually works svn path=/trunk/externals/io/; revision=7687 --- wiiremote/aka.wiiremote.c | 443 +++++++++++++------ wiiremote/wiiremote.c | 1026 ++++++++++++++++++++++++++++++++++----------- wiiremote/wiiremote.h | 123 +++++- 3 files changed, 1215 insertions(+), 377 deletions(-) diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 5780c43..9d945b1 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -1,12 +1,18 @@ // aka.wiiremote.c // Copyright by Masayuki Akamatsu +// Code for PD by Hans-Christoph Steiner // 1.0B1 : 2006.12.12 // 1.0B2 : 2006.12.15 // 1.0B3 : 2006.12.20 +// 1.0B4 : 2006.12.24 +// 1.0B5 : 2007.02.03 +// 1.0B6 : 2007.04.24 #ifdef PD #include "m_pd.h" +#define SETSYM SETSYMBOL #define SETLONG SETFLOAT +#define method t_method static t_class *wiiremote_class; #else /* Max */ #include "ext.h" @@ -27,36 +33,42 @@ typedef struct _akawiiremote #endif WiiRemoteRef wiiremote; + char address[32]; void *clock; - long interval; - long trial; + Boolean connected; void *statusOut; - void *buttonsOut; - void *irOut; - void *accOut; + void *dataOut } t_akawiiremote; void *akawiiremote_class; // the number of instance of this object void akawiiremote_bang(t_akawiiremote *x); +void akawiiremote_address(t_akawiiremote *x, t_symbol *s); void akawiiremote_connect(t_akawiiremote *x); void akawiiremote_disconnect(t_akawiiremote *x); void akawiiremote_motionsensor(t_akawiiremote *x, long enable); void akawiiremote_irsensor(t_akawiiremote *x, long enable); void akawiiremote_vibration(t_akawiiremote *x, long enable); void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4); +void akawiiremote_expansion(t_akawiiremote *x, long enable); -void akawiiremote_getbatterylevel(t_akawiiremote *x); -void akawiiremote_getexpansionstatus(t_akawiiremote *x); -void akawiiremote_getledstatus(t_akawiiremote *x); +void akawiiremote_getbattery(t_akawiiremote *x); +void akawiiremote_getexpansion(t_akawiiremote *x); +void akawiiremote_getled(t_akawiiremote *x); +void akawiiremote_getaddress(t_akawiiremote *x); +void akawiiremote_getcalibration(t_akawiiremote *x); void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s); void akawiiremote_clock(t_akawiiremote *x); void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); void akawiiremote_free(t_akawiiremote *x); +char remoteStr[] = "remote"; +char nunchukStr[] = "nunchuk"; +char classicStr[] = "classic"; + #ifdef PD void wiiremote_setup() #else /* Max */ @@ -66,6 +78,8 @@ void main() NumVersion outSoftwareVersion; BluetoothHCIVersionInfo outHardwareVersion; + post("aka.wiiremote 1.0B6-UB by Masayuki Akamatsu"); + if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) { if (outSoftwareVersion.majorRev < 1 || outSoftwareVersion.minorAndBugRev < 0x63) @@ -80,8 +94,6 @@ void main() return; } - post("aka.wiiremote 1.0B4-UB by Masayuki Akamatsu"); - #ifdef PD post("\tPd port by Hans-Christoph Steiner"); @@ -95,30 +107,35 @@ void main() class_addbang(wiiremote_class,(t_method)akawiiremote_bang); class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motion"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("ir"), A_DEFFLOAT, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getbattery,gensym("getbattery"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansion,gensym("getexpansion"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getled,gensym("getled"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); #else /* Max */ setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); addbang((method)akawiiremote_bang); - addmess((method)akawiiremote_connect,"connect",0); + addmess((method)akawiiremote_address,"address",A_DEFSYM, 0); + addmess((method)akawiiremote_connect,"connect", 0); addmess((method)akawiiremote_disconnect,"disconnect",0); - addmess((method)akawiiremote_motionsensor,"motionsensor", A_DEFLONG, 0); - addmess((method)akawiiremote_irsensor,"irsensor", A_DEFLONG, 0); + addmess((method)akawiiremote_motionsensor,"motion", A_DEFLONG, 0); + addmess((method)akawiiremote_irsensor,"ir", A_DEFLONG, 0); addmess((method)akawiiremote_vibration,"vibration", A_DEFLONG, 0); addmess((method)akawiiremote_led,"led", A_DEFLONG, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0); - - addmess((method)akawiiremote_getbatterylevel,"getbatterylevel",0); - addmess((method)akawiiremote_getexpansionstatus,"getexpansionstatus",0); - addmess((method)akawiiremote_getledstatus,"getledstatus",0); + addmess((method)akawiiremote_expansion,"expansion", A_DEFLONG, 0); + addmess((method)akawiiremote_expansion,"nunchuk", A_DEFLONG, 0); + + addmess((method)akawiiremote_getbattery,"getbattery",0); + addmess((method)akawiiremote_getexpansion,"getexpansion",0); + addmess((method)akawiiremote_getled,"getled",0); + addmess((method)akawiiremote_getaddress,"getaddress",0); + addmess((method)akawiiremote_getcalibration,"getcalibration", 0); addmess((method)akawiiremote_assist,"assist",A_CANT,0); #endif /* PD */ @@ -128,38 +145,114 @@ void main() void akawiiremote_bang(t_akawiiremote *x) { - t_atom list[4]; + t_atom av[5]; if (x->wiiremote->device == nil) return; // do nothing -#ifdef PD - outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); -#else /* Max */ - outlet_int(x->buttonsOut, x->wiiremote->buttonData); -#endif /* PD */ +//#ifdef PD +// outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); +//#else /* Max */ +//#endif /* PD */ + + if (x->wiiremote->isExpansionPortAttached && x->wiiremote->isExpansionPortEnabled) + { + // Classic Controller + if (x->wiiremote->expType == WiiClassicController) + { + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->cButtonData); + outlet_anything(x->dataOut, gensym(classicStr), 2, av); + + // Joystick 1 + SETSYM(av, gensym("stick1")); + SETLONG(av + 1, x->wiiremote->cStickX1); + SETLONG(av + 2, x->wiiremote->cStickY1); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + + // Joystick 2 + SETSYM(av, gensym("stick2")); + SETLONG(av + 1, x->wiiremote->cStickX2); + SETLONG(av + 2, x->wiiremote->cStickY2); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + + // Analog + SETSYM(av, gensym("analog")); + SETLONG(av + 1, x->wiiremote->cAnalogL); + SETLONG(av + 2, x->wiiremote->cAnalogR); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + } + + // Nunchuk + if (x->wiiremote->expType == WiiNunchuk) + { + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->nButtonData); + outlet_anything(x->dataOut, gensym(nunchukStr), 2, av); + + // Joystick + SETSYM(av, gensym("stick")); + SETLONG(av + 1, x->wiiremote->nStickX); + SETLONG(av + 2, x->wiiremote->nStickY); + outlet_anything(x->dataOut, gensym(nunchukStr), 3, av); + + // Motion Sensor + if (x->wiiremote->isMotionSensorEnabled) + { + SETSYM(av, gensym("motion")); + SETLONG(av + 1, x->wiiremote->nAccX); + SETLONG(av + 2, x->wiiremote->nAccY); + SETLONG(av + 3, x->wiiremote->nAccZ); + SETLONG(av + 4, x->wiiremote->nOrientation); + outlet_anything(x->dataOut, gensym(nunchukStr), 5, av); + } + } + } + + // Wii Remote + + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->buttonData); + outlet_anything(x->dataOut, gensym(remoteStr), 2, av); + // IR Sensor if (x->wiiremote->isIRSensorEnabled) { - SETFLOAT(list, x->wiiremote->posX); - SETFLOAT(list + 1, x->wiiremote->posY); - SETFLOAT(list + 2, x->wiiremote->angle); - SETLONG (list + 3, x->wiiremote->tracking); - outlet_list(x->irOut, 0L, 4, list); + SETSYM(av, gensym("ir")); + SETFLOAT(av + 1, x->wiiremote->posX); // posX and posY are "float"???? + SETFLOAT(av + 2, x->wiiremote->posY); + SETFLOAT(av + 3, x->wiiremote->angle); + SETLONG (av + 4, x->wiiremote->tracking); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); } + // Motion Sensor if (x->wiiremote->isMotionSensorEnabled) { - SETLONG(list, x->wiiremote->accX); - SETLONG(list + 1, x->wiiremote->accY); - SETLONG(list + 2, x->wiiremote->accZ); - SETLONG(list + 3, x->wiiremote->orientation); - outlet_list(x->accOut, 0L, 4, list); + SETSYM(av, gensym("motion")); + SETLONG(av + 1, x->wiiremote->accX); + SETLONG(av + 2, x->wiiremote->accY); + SETLONG(av + 3, x->wiiremote->accZ); + SETLONG(av + 4, x->wiiremote->orientation); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); } - - //wiiremote_getstatus(); // stopped in B3 } +//-------------------------------------------------------------------------------------------- + +void akawiiremote_address(t_akawiiremote *x, t_symbol *s) +{ + if (*(s->s_name) == 0) // if null string + *(x->address) = 0; + else + strcpy(x->address, s->s_name); +} + +//-------------------------------------------------------------------------------------------- + void akawiiremote_connect(t_akawiiremote *x) { t_atom status; @@ -172,8 +265,8 @@ void akawiiremote_connect(t_akawiiremote *x) } else { - result = wiiremote_search(x->wiiremote); // start searching the device - x->trial = 0; + result = wiiremote_search(x->wiiremote, x->address); // start searching the device + x->connected = false; clock_unset(x->clock); // stop clock clock_delay(x->clock, 0); // start clock to check the device found } @@ -188,97 +281,208 @@ void akawiiremote_disconnect(t_akawiiremote *x) Boolean result; t_atom status; + clock_unset(x->clock); // stop clock + wiiremote_stopsearch(x->wiiremote); + result = wiiremote_disconnect(x->wiiremote); SETLONG(&status, result); - outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); + outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); + + x->connected = !result; } +//-------------------------------------------------------------------------------------------- + void akawiiremote_motionsensor(t_akawiiremote *x, long enable) { - wiiremote_motionsensor(x->wiiremote, enable); + Boolean result; + t_atom status; + + result = wiiremote_motionsensor(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("motion"), 1, &status); } void akawiiremote_irsensor(t_akawiiremote *x, long enable) { - wiiremote_irsensor(x->wiiremote, enable); + Boolean result; + t_atom status; + + result = wiiremote_irsensor(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("ir"), 1, &status); +} + +void akawiiremote_expansion(t_akawiiremote *x, long enable) +{ + Boolean result; + t_atom status; + + result = wiiremote_expansion(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("nunchuk"), 1, &status); } void akawiiremote_vibration(t_akawiiremote *x, long enable) { - wiiremote_vibration(x->wiiremote, enable); + Boolean result; + t_atom status; + + result = wiiremote_vibration(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("vibration"), 1, &status); } void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) { - wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); + Boolean result; + t_atom status; + + result = wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("led"), 1, &status); } //-------------------------------------------------------------------------------------------- -void akawiiremote_getbatterylevel(t_akawiiremote *x) +void akawiiremote_getbattery(t_akawiiremote *x) { - t_atom status; + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("battery"), 0, nil); + } + else + { + t_atom status; + + SETFLOAT(&status, x->wiiremote->batteryLevel); + outlet_anything(x->statusOut, gensym("battery"), 1, &status); + } +} + +void akawiiremote_getexpansion(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("expansion"), 0, nil); + } + else + { + t_atom status; + if (x->wiiremote->isExpansionPortAttached) + SETLONG(&status, x->wiiremote->expType); + else + SETLONG(&status, 0); + outlet_anything(x->statusOut, gensym("expansion"), 1, &status); + } +} - SETFLOAT(&status, x->wiiremote->batteryLevel); - outlet_anything(x->statusOut, gensym("batterylevel"), 1, &status); +void akawiiremote_getled(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("led"), 0, nil); + } + else + { + t_atom list[4]; + + SETLONG(list, x->wiiremote->isLED1Illuminated); + SETLONG(list + 1, x->wiiremote->isLED2Illuminated); + SETLONG(list + 2, x->wiiremote->isLED3Illuminated); + SETLONG(list + 3, x->wiiremote->isLED4Illuminated); + outlet_anything(x->statusOut, gensym("led"), 4, list); + } } -void akawiiremote_getexpansionstatus(t_akawiiremote *x) +void akawiiremote_getcalibration(t_akawiiremote *x) { - t_atom status; - - SETLONG(&status, x->wiiremote->isExpansionPortUsed); - outlet_anything(x->statusOut, gensym("expansionstatus"), 1, &status); + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("calibration"), 0, nil); + } + else + { + t_atom list[8]; + + if (x->wiiremote->isExpansionPortAttached) + { + SETSYM(list, gensym(nunchukStr)); + SETSYM(list + 1, gensym("stick")); + SETLONG(list + 2, x->wiiremote->nunchukJoyStickCalibData.x_max); + SETLONG(list + 3, x->wiiremote->nunchukJoyStickCalibData.x_min); + SETLONG(list + 4, x->wiiremote->nunchukJoyStickCalibData.x_center); + SETLONG(list + 5, x->wiiremote->nunchukJoyStickCalibData.y_max); + SETLONG(list + 6, x->wiiremote->nunchukJoyStickCalibData.y_min); + SETLONG(list + 7, x->wiiremote->nunchukJoyStickCalibData.y_center); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + + SETSYM(list + 1, gensym("motion")); + SETLONG(list + 2, x->wiiremote->nunchukCalibData.accX_zero); + SETLONG(list + 3, x->wiiremote->nunchukCalibData.accY_zero); + SETLONG(list + 4, x->wiiremote->nunchukCalibData.accZ_zero); + SETLONG(list + 5, x->wiiremote->nunchukCalibData.accX_1g); + SETLONG(list + 6, x->wiiremote->nunchukCalibData.accY_1g); + SETLONG(list + 7, x->wiiremote->nunchukCalibData.accZ_1g); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + } + + SETSYM(list, gensym(remoteStr)); + SETSYM(list + 1, gensym("motion")); + SETLONG(list + 2, x->wiiremote->wiiCalibData.accX_zero); + SETLONG(list + 3, x->wiiremote->wiiCalibData.accY_zero); + SETLONG(list + 4, x->wiiremote->wiiCalibData.accZ_zero); + SETLONG(list + 5, x->wiiremote->wiiCalibData.accX_1g); + SETLONG(list + 6, x->wiiremote->wiiCalibData.accY_1g); + SETLONG(list + 7, x->wiiremote->wiiCalibData.accZ_1g); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + } } -void akawiiremote_getledstatus(t_akawiiremote *x) +//-------------------------------------------------------------------------------------------- + +void akawiiremote_getaddress(t_akawiiremote *x) { - t_atom list[4]; - - SETLONG(list, x->wiiremote->isLED1Illuminated); - SETLONG(list + 1, x->wiiremote->isLED2Illuminated); - SETLONG(list + 2, x->wiiremote->isLED3Illuminated); - SETLONG(list + 3, x->wiiremote->isLED4Illuminated); - outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("address"), 0, nil); + } + else + { + char str[32]; + t_atom address; + + wiiremote_getaddress(x->wiiremote, str); + SETSYM(&address, gensym(str)); + outlet_anything(x->statusOut, gensym("address"), 1, &address); + } } //-------------------------------------------------------------------------------------------- void akawiiremote_clock(t_akawiiremote *x) { - //Boolean result; + Boolean connection; t_atom status; - if (wiiremote_isconnected(x->wiiremote)) // if the device is connected... + connection = wiiremote_isconnected(x->wiiremote); + + if (x->connected == false && connection == true) // if the device is connected... { - clock_unset(x->clock); // stop clock - - wiiremote_stopsearch(x->wiiremote); - //result = wiiremote_connect(); // remove in B3 - wiiremote_getstatus(x->wiiremote); // add in B3 + wiiremote_getstatus(x->wiiremote); + x->connected = true; SETLONG(&status, 1); outlet_anything(x->statusOut, gensym("connect"), 1, &status); } - else // if the device is not connected... + + if (x->connected == true && connection == false) { - x->trial++; - //SETLONG(&status, x->trial); - //outlet_anything(x->statusOut, gensym("searching"), 1, &status); - - if (x->trial >= kMaxTrial) // if trial is over - { - clock_unset(x->clock); // stop clock - - wiiremote_stopsearch(x->wiiremote); - SETLONG(&status, 0); - outlet_anything(x->statusOut, gensym("connect"), 1, &status); - } - else - { - //post("trial %d",x->trial); - clock_delay(x->clock, x->interval); // restart clock - } + x->connected = false; + SETLONG(&status, 0); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); } + + clock_delay(x->clock, kInterval); // restart clock } //-------------------------------------------------------------------------------------------- @@ -295,10 +499,8 @@ void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) { switch(a) { - case 0: sprintf(s,"list(acc-x acc-y acc-z orientation)"); break; - case 1: sprintf(s,"list(pos-x pos-y angle tracking)"); break; - case 2: sprintf(s,"int(buttons)"); break; - case 3: sprintf(s,"message(status)"); break; + case 0: sprintf(s,"data messages"); break; + case 2: sprintf(s,"status messages"); break; } } } @@ -307,48 +509,55 @@ void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) { -#ifdef PD - t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); - - x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); // add in 1.0B4 - if (x->wiiremote != nil) - wiiremote_init(x->wiiremote); - - x->clock = clock_new(x, (t_method)akawiiremote_clock); - - /* create anything outlet used for HID data */ - x->statusOut = outlet_new(&x->x_obj, 0); - x->buttonsOut = outlet_new(&x->x_obj, &s_float); - x->irOut = outlet_new(&x->x_obj, &s_list); - x->accOut = outlet_new(&x->x_obj, &s_list); -#else /* Max */ t_akawiiremote *x; +#ifdef PD + x = (t_akawiiremote *)pd_new(wiiremote_class); +#else /* Max */ x = (t_akawiiremote *)newobject(akawiiremote_class); +#endif /* PD */ - x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); // add in 1.0B4 + x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); if (x->wiiremote != nil) + { wiiremote_init(x->wiiremote); + x->wiiremote->isMotionSensorEnabled = true; + x->wiiremote->isIRSensorEnabled = false; + x->wiiremote->isVibrationEnabled = false; + x->wiiremote->isExpansionPortEnabled = false; + x->wiiremote->isLED1Illuminated = false; + x->wiiremote->isLED2Illuminated = false; + x->wiiremote->isLED3Illuminated = false; + x->wiiremote->isLED4Illuminated = false; + } x->clock = clock_new(x, (method)akawiiremote_clock); +#ifdef PD + if (ac>0 && av[0].a_type == A_SYMBOL) + strcpy(x->address, av[0].a_w.w_symbol->s_name); + + x->statusOut = outlet_new(&x->x_obj, 0); + x->dataOut = outlet_new(&x->x_obj, 0); +#else /* Max */ + if (ac>0 && av[0].a_type == A_SYM) + strcpy(x->address, av[0].a_w.w_sym->s_name); x->statusOut = outlet_new(x, 0); - x->buttonsOut = intout(x); - x->irOut = listout(x); - x->accOut = listout(x); + x->dataOut = outlet_new(x, 0); #endif /* PD */ - x->trial = 0; - x->interval = kInterval; + x->connected = false; return x; } void akawiiremote_free(t_akawiiremote *x) { - if (x->wiiremote != nil) // add in 1.0B4 + if (x->wiiremote != nil) { - wiiremote_disconnect(x->wiiremote); - freebytes(x->wiiremote, sizeof(WiiRemoteRec)); // add in 1.0B4 + if (wiiremote_isconnected(x->wiiremote)) + wiiremote_disconnect(x->wiiremote); + freebytes(x->wiiremote, sizeof(WiiRemoteRec)); + x->wiiremote = nil; } clock_unset(x->clock); diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c index cabbb6e..2caffb7 100644 --- a/wiiremote/wiiremote.c +++ b/wiiremote/wiiremote.c @@ -9,8 +9,16 @@ typedef unsigned char darr[]; #define kTrial 10 +#define kWait 10000 +// the unit of kWait is microseconds, thus 10000 means 10ms + +#define kWiiIRPixelsWidth 1024.0 +#define kWiiIRPixelsHeight 768.0 + + +Boolean requestUpdates(WiiRemoteRef wiiremote); +void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event); -//static WiiRemoteRec gWiiRemote; // remove in 1.0B4 //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- @@ -22,41 +30,203 @@ void wiiremote_init(WiiRemoteRef wiiremote) wiiremote->ichan = nil; wiiremote->cchan = nil; + wiiremote->address = nil; + wiiremote->accX = 0x10; wiiremote->accY = 0x10; wiiremote->accZ = 0x10; wiiremote->buttonData = 0; + + wiiremote->lowZ = 0; + wiiremote->lowX = 0; wiiremote->leftPoint = -1; wiiremote->tracking = false; wiiremote->batteryLevel = 0; - wiiremote->isIRSensorEnabled = false; + wiiremote->readingRegister = false; wiiremote->isMotionSensorEnabled = false; wiiremote->isVibrationEnabled = false; + wiiremote->isIRSensorEnabled = false; + wiiremote->wiiIRMode = kWiiIRModeExtended; + wiiremote->isExpansionPortEnabled = false; + wiiremote->isExpansionPortAttached = false; + wiiremote->expType = WiiExpNotAttached; - wiiremote->isExpansionPortUsed = false; wiiremote->isLED1Illuminated = false; wiiremote->isLED2Illuminated = false; wiiremote->isLED3Illuminated = false; wiiremote->isLED4Illuminated = false; + + wiiremote->nAccX = 0x10; + wiiremote->nAccY = 0x10; + wiiremote->nAccZ = 0x10; + wiiremote->nButtonData = 0; + + wiiremote->nLowZ = 0; + wiiremote->nLowX = 0; + } //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- -void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) +Boolean openCChan(WiiRemoteRef wiiremote) { - CFStringRef myString; + short i; + IOReturn ret; + + // open L2CAPChannel : BluetoothL2CAPPSM = 17 + for (i=0; idevice, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) + { + wiiremote->cchan = nil; + IOBluetoothDeviceCloseConnection(wiiremote->device); + return false; + } + IOBluetoothObjectRetain(wiiremote->cchan); + + return (ret==kIOReturnSuccess); +} - myString = IOBluetoothDeviceGetName(device); - if (myString != nil) +Boolean openIChan(WiiRemoteRef wiiremote) +{ + short i; + IOReturn ret; + + // open L2CAPChannel : BluetoothL2CAPPSM = 19 + for (i=0; idevice, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) { - if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) + wiiremote->ichan = nil; + IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); + IOBluetoothObjectRelease(wiiremote->cchan); + IOBluetoothDeviceCloseConnection(wiiremote->device); + return false; + } + IOBluetoothObjectRetain(wiiremote->ichan); + + return (ret==kIOReturnSuccess); +} + +//-------------------------------------------------------------------------------------------- + +Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, unsigned short length) +{ + unsigned char buf[40]; + IOReturn ret; + int i; + + memset(buf,0,40); + buf[0] = 0x52; + memcpy(buf+1, data, length); + if (buf[1] == 0x16) + length=23; + else + length++; + + usleep(kWait); // wait 10ms // Done to make sure commands don't happen too fast. + + for (i = 0; icchan, buf, length); + if (ret == kIOReturnSuccess) + break; + usleep(kWait); + } + + if (ret != kIOReturnSuccess) + wiiremote_disconnect(wiiremote); + + return (ret==kIOReturnSuccess); +} + +Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, unsigned short length) +{ + unsigned char cmd[22]; + int i; + unsigned long addr = address; + + + for(i=0 ; i>24) & 0xFF; + cmd[2] = (addr>>16) & 0xFF; + cmd[3] = (addr>> 8) & 0xFF; + cmd[4] = (addr>> 0) & 0xFF; + cmd[5] = length; + + // and of course the vibration flag, as usual + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + + data = cmd; + + return sendCommand(wiiremote, cmd, 22); +} + +Boolean readData(WiiRemoteRef wiiremote, unsigned long address, unsigned short length) +{ + + unsigned char cmd[7]; + unsigned long addr = address; + unsigned short len = length; + + cmd[0] = 0x17; + cmd[1] = (addr>>24)&0xFF; + cmd[2] = (addr>>16)&0xFF; + cmd[3] = (addr>> 8)&0xFF; + cmd[4] = (addr>> 0)&0xFF; + + cmd[5] = (len >> 8)&0xFF; + cmd[6] = (len >> 0)&0xFF; + + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (cmd[1] & 0x02) wiiremote->readingRegister = true; + + return sendCommand(wiiremote, cmd, 7); +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) +{ + CFStringRef name; + CFStringRef address; + + if (wiiremote_isconnected(wiiremote)) + return; + + name = IOBluetoothDeviceGetName(device); + address = IOBluetoothDeviceGetAddressString(device); + if (name != nil && address != nil) + { + if (CFStringCompare(name, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) { - wiiremote->device = IOBluetoothObjectRetain(device); - if ( !wiiremote_connect(wiiremote)) // add in B3 - wiiremote_disconnect(wiiremote); // add in B3 + if ( CFStringGetLength(wiiremote->address) == 0 + || CFStringCompare(address, wiiremote->address, kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + wiiremote->device = IOBluetoothObjectRetain(device); + if ( wiiremote_connect(wiiremote) == false ) + wiiremote_disconnect(wiiremote); + } } } } @@ -73,12 +243,23 @@ void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoot void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) { + IOReturn ret; + if (aborted) return; // called by stop ;) if (error != kIOReturnSuccess) + { + wiiremote_stopsearch((WiiRemoteRef)refCon); + return; + } + + /* + ret = IOBluetoothDeviceInquiryStart(((WiiRemoteRef)refCon)->inquiry); + if (ret != kIOReturnSuccess) { wiiremote_stopsearch((WiiRemoteRef)refCon); } + */ } //-------------------------------------------------------------------------------------------- @@ -91,7 +272,7 @@ Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) return result; } -Boolean wiiremote_search(WiiRemoteRef wiiremote) +Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) { IOReturn ret; @@ -102,6 +283,10 @@ Boolean wiiremote_search(WiiRemoteRef wiiremote) IOBluetoothDeviceInquirySetDeviceFoundCallback(wiiremote->inquiry, myFoundFunc); IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(wiiremote->inquiry, myUpdatedFunc); IOBluetoothDeviceInquirySetCompleteCallback(wiiremote->inquiry, myCompleteFunc); + + if (wiiremote->address != nil) + CFRelease(wiiremote->address); + wiiremote->address = CFStringCreateWithCString(nil, address, kCFStringEncodingMacRoman); ret = IOBluetoothDeviceInquiryStart(wiiremote->inquiry); if (ret != kIOReturnSuccess) @@ -138,125 +323,414 @@ Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- - void myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon) +unsigned char decrypt(unsigned char data) { - WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; - unsigned char *dp = (unsigned char*)data; + return (data ^ 0x17) + 0x17; +} - if (dp[1] == 0x20 && length >= 8) +//-------------------------------------------------------------------------------------------- + +/** +* Handle report 0x21 (Read Data) from wiimote. + * dp[0] = Bluetooth header + * dp[1] = (0x21) Report/Channel ID + * dp[2] = Wiimote Buttons + * dp[3] = Wiimote Buttons + * dp[4] = High 4 bits = payload size; Low 4 bits = Error flag (0 = all good) + * dp[5] = Offset of memory read + * dp[6] = Offset of memory read + * dp[7+] = the Data. + **/ + +void handleRAMData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + // specify attached expasion device + if ((dp[5] == 0x00) && (dp[6] == 0xF0)) { - wiiremote->batteryLevel = (double)dp[7]; - wiiremote->batteryLevel /= (double)0xC0; - - wiiremote->isExpansionPortUsed = (dp[4] & 0x02) != 0; - wiiremote->isLED1Illuminated = (dp[4] & 0x10) != 0; - wiiremote->isLED2Illuminated = (dp[4] & 0x20) != 0; - wiiremote->isLED3Illuminated = (dp[4] & 0x40) != 0; - wiiremote->isLED4Illuminated = (dp[4] & 0x80) != 0; - - //have to reset settings (vibration, motion, IR and so on...) - wiiremote_irsensor(wiiremote, wiiremote->isIRSensorEnabled); + if (decrypt(dp[21]) == 0x00) + { + wiiremote->expType = WiiNunchuk; + } + else + if (decrypt(dp[21]) == 0x01) + { + wiiremote->expType = WiiClassicController; + } + else + { + wiiremote->expType = WiiExpNotAttached; + } + // initExpPort = NO; + return; } + + // wiimote calibration data + if (!wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) + { + wiiremote->wiiCalibData.accX_zero = dp[7]; + wiiremote->wiiCalibData.accY_zero = dp[8]; + wiiremote->wiiCalibData.accZ_zero = dp[9]; + + //dp[10] - unknown/unused + + wiiremote->wiiCalibData.accX_1g = dp[11]; + wiiremote->wiiCalibData.accY_1g = dp[12]; + wiiremote->wiiCalibData.accZ_1g = dp[13]; + return; + } + + // expansion device calibration data. + if (wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) + { + if (wiiremote->expType == WiiNunchuk) + { + //nunchuk calibration data + wiiremote->nunchukCalibData.accX_zero = decrypt(dp[7]); + wiiremote->nunchukCalibData.accY_zero = decrypt(dp[8]); + wiiremote->nunchukCalibData.accZ_zero = decrypt(dp[9]); + + wiiremote->nunchukCalibData.accX_1g = decrypt(dp[11]); + wiiremote->nunchukCalibData.accY_1g = decrypt(dp[12]); + wiiremote->nunchukCalibData.accZ_1g = decrypt(dp[13]); + + wiiremote->nunchukJoyStickCalibData.x_max = decrypt(dp[15]); + wiiremote->nunchukJoyStickCalibData.x_min = decrypt(dp[16]); + wiiremote->nunchukJoyStickCalibData.x_center = decrypt(dp[17]); + + wiiremote->nunchukJoyStickCalibData.y_max = decrypt(dp[18]); + wiiremote->nunchukJoyStickCalibData.y_min = decrypt(dp[19]); + wiiremote->nunchukJoyStickCalibData.y_center = decrypt(dp[20]); + + return; + } + else + if (wiiremote->expType == WiiClassicController) + { + //classic controller calibration data (probably) + } + } + + // wii remote buttons + wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; +} + +void handleStatusReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + wiiremote->batteryLevel = (double)dp[7]; + wiiremote->batteryLevel /= (double)0xC0; // C0 = fully charged. + + if ((dp[4] & 0x02)) //some device attached to Wiimote + { + wiiremote->isExpansionPortAttached = true; + // initExpPort = YES; + + Boolean ret = writeData(wiiremote, (darr){0x00}, 0x04A40040, 1); // Initialize the device + + if (ret == false) + { + wiiremote->isExpansionPortAttached = false; + return; + } + + usleep(kWait); // Give the write a chance to be processed. + + ret = readData(wiiremote, 0x04A400F0, 16); // read expansion device type + if (ret == false) + { + wiiremote->isExpansionPortAttached = false; + } + } + else + { // unplugged + wiiremote->isExpansionPortAttached = false; + wiiremote->expType = WiiExpNotAttached; + } + + if (dp[4] & 0x10) + wiiremote->isLED1Illuminated = true; + else + wiiremote->isLED1Illuminated = false; + + if (dp[4] & 0x20) + wiiremote->isLED2Illuminated = true; + else + wiiremote->isLED2Illuminated = false; + + if (dp[4] & 0x40) + wiiremote->isLED3Illuminated = true; + else + wiiremote->isLED3Illuminated = false; + + if (dp[4] & 0x80) + wiiremote->isLED4Illuminated = true; + else + wiiremote->isLED4Illuminated = false; +} - if ((dp[1]&0xF0) == 0x30) +void handleExtensionData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + unsigned char startByte; + + switch (dp[1]) { + case 0x34 : + startByte = 4; + break; + case 0x35 : + startByte = 7; + break; + case 0x36 : + startByte = 14; + break; + case 0x37 : + startByte = 17; + break; + default: + return; // This shouldn't ever happen. + break; + } + + if (wiiremote->expType == WiiNunchuk) { - wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; - - if (dp[1] & 0x01) + wiiremote->nStickX = decrypt(dp[startByte]); + wiiremote->nStickY = decrypt(dp[startByte +1]); + wiiremote->nAccX = decrypt(dp[startByte +2]); + wiiremote->nAccY = decrypt(dp[startByte +3]); + wiiremote->nAccZ = decrypt(dp[startByte +4]); + wiiremote->nButtonData = decrypt(dp[startByte +5]); + + wiiremote->nLowZ = wiiremote->nLowZ * .9 + wiiremote->nAccZ * .1; + wiiremote->nLowX = wiiremote->nLowX * .9 + wiiremote->nAccX * .1; + + float absx = abs(wiiremote->nLowX - 128); + float absz = abs(wiiremote->nLowZ - 128); + + if (wiiremote->nOrientation == 0 || wiiremote->nOrientation == 2) absx -= 5; + if (wiiremote->nOrientation == 1 || wiiremote->nOrientation == 3) absz -= 5; + + if (absz >= absx) { - wiiremote->accX = dp[4]; - wiiremote->accY = dp[5]; - wiiremote->accZ = dp[6]; - - wiiremote->lowZ = wiiremote->lowZ * .9 + wiiremote->accZ * .1; - wiiremote->lowX = wiiremote->lowX * .9 + wiiremote->accX * .1; - - float absx = abs(wiiremote->lowX - 128); - float absz = abs(wiiremote->lowZ - 128); - - if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; - if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; - - if (absz >= absx) - { - if (absz > 5) - wiiremote->orientation = (wiiremote->lowZ > 128) ? 0 : 2; - } - else - { - if (absx > 5) - wiiremote->orientation = (wiiremote->lowX > 128) ? 3 : 1; - } - //printf("orientation: %d\n", orientation); + if (absz > 5) + wiiremote->nOrientation = (wiiremote->nLowZ > 128) ? 0 : 2; } - - if (dp[1] & 0x02) + else { - int i; - for(i=0 ; i<4 ; i++) - { - wiiremote->irData[i].x = dp[7 + 3*i]; - wiiremote->irData[i].y = dp[8 + 3*i]; - wiiremote->irData[i].s = dp[9 + 3*i]; - wiiremote->irData[i].x += (wiiremote->irData[i].s & 0x30) << 4; - wiiremote->irData[i].y += (wiiremote->irData[i].s & 0xC0) << 2; - wiiremote->irData[i].s &= 0x0F; - } + if (absx > 5) + wiiremote->nOrientation = (wiiremote->nLowX > 128) ? 3 : 1; } } + else + if (wiiremote->expType == WiiClassicController) + { + wiiremote->cButtonData = (unsigned short)(decrypt(dp[startByte + 4]) << 8) + decrypt(dp[startByte + 5]); + wiiremote->cButtonData = ~wiiremote->cButtonData; // bit reverse + + wiiremote->cStickX1 = decrypt(dp[startByte]) & 0x3F; + wiiremote->cStickY1 = decrypt(dp[startByte + 1]) & 0x3F; - float ox, oy; + wiiremote->cStickX2 = (((decrypt(dp[startByte +0]) & 0xC0) >> 3) | + ((decrypt(dp[startByte +1]) & 0xC0) >> 5) | + ((decrypt(dp[startByte +2]) & 0x80) >> 7)) & 0x1F; + wiiremote->cStickY2 = decrypt(dp[startByte + 2]) & 0x1F; + + wiiremote->cAnalogL = (((decrypt(dp[startByte +2]) & 0x60) >> 2) | + ((decrypt(dp[startByte +3]) & 0xE0) >> 5)) & 0x1F; + wiiremote->cAnalogR = decrypt(dp[startByte + 3]) & 0x1F; + } +} - if (wiiremote->irData[0].s < 0x0F && wiiremote->irData[1].s < 0x0F) +void handleIRData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + int i; + + if (dp[1] == 0x33) + { // 12 IR bytes + int startByte = 0; + for(i=0 ; i < 4 ; i++) + { + startByte = 7 + 3 * i; + wiiremote->irData[i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; + wiiremote->irData[i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; + wiiremote->irData[i].s = dp[startByte +2] & 0x0F; + } + } + else + { // 10 IR bytes + int shift = (dp[1] == 0x36) ? 4 : 7; + int startByte = 0; + for (i=0; i < 2; i++) { + startByte = shift + 5 * i; + wiiremote->irData[2*i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; + wiiremote->irData[2*i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; + wiiremote->irData[2*i].s = ((wiiremote->irData[2*i].x == wiiremote->irData[2*i].y) && (wiiremote->irData[2*i].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. + + wiiremote->irData[(2*i)+1].x = (dp[startByte +3] | ((dp[startByte +2] & 0x03) << 8)) & 0x3FF; + wiiremote->irData[(2*i)+1].y = (dp[startByte +4] | ((dp[startByte +2] & 0x0C) << 6)) & 0x3FF; + wiiremote->irData[(2*i)+1].s = ((wiiremote->irData[(2*i)+1].x == wiiremote->irData[(2*i)+1].y) && (wiiremote->irData[(2*i)+1].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. + } + } + + int p1 = -1; + int p2 = -1; + // we should modify this loop to take the points with the lowest s (the brightest ones) + for (i=0 ; i<4 ; i++) { + if (p1 == -1) { + if (wiiremote->irData [i].s < 0x0F) + p1 = i; + } else { + if (wiiremote->irData [i].s < 0x0F) { + p2 = i; + break; + } + } + } + + double ox, oy; + if ((p1 > -1) && (p2 > -1)) { - int l = wiiremote->leftPoint, r; + int l = wiiremote->leftPoint; if (wiiremote->leftPoint == -1) { - // printf("Tracking.\n"); switch (wiiremote->orientation) { - case 0: l = (wiiremote->irData[0].x < wiiremote->irData[1].x) ? 0 : 1; break; - case 1: l = (wiiremote->irData[0].y > wiiremote->irData[1].y) ? 0 : 1; break; - case 2: l = (wiiremote->irData[0].x > wiiremote->irData[1].x) ? 0 : 1; break; - case 3: l = (wiiremote->irData[0].y < wiiremote->irData[1].y) ? 0 : 1; break; + case 0: l = (wiiremote->irData[p1].x < wiiremote->irData[p2].x) ? 0 : 1; break; + case 1: l = (wiiremote->irData[p1].y > wiiremote->irData[p2].y) ? 0 : 1; break; + case 2: l = (wiiremote->irData[p1].x > wiiremote->irData[p2].x) ? 0 : 1; break; + case 3: l = (wiiremote->irData[p1].y < wiiremote->irData[p2].y) ? 0 : 1; break; } + wiiremote->leftPoint = l; } - r = 1-l; - - float dx = wiiremote->irData[r].x - wiiremote->irData[l].x; - float dy = wiiremote->irData[r].y - wiiremote->irData[l].y; - - float d = sqrt(dx*dx+dy*dy); - + int r = 1-l; + + double dx = wiiremote->irData[r].x - wiiremote->irData[l].x; + double dy = wiiremote->irData[r].y - wiiremote->irData[l].y; + double d = hypot (dx, dy); + dx /= d; dy /= d; - - float cx = (wiiremote->irData[l].x+wiiremote->irData[r].x)/1024.0 - 1; - float cy = (wiiremote->irData[l].y+wiiremote->irData[r].y)/1024.0 - .75; - - wiiremote->angle = atan2(dy, dx); - + + double cx = (wiiremote->irData[l].x + wiiremote->irData[r].x)/kWiiIRPixelsWidth - 1; + double cy = (wiiremote->irData[l].y + wiiremote->irData[r].y)/kWiiIRPixelsHeight - 1; + ox = -dy*cy-dx*cx; oy = -dx*cy+dy*cx; - //printf("x:%5.2f; y: %5.2f; angle: %5.1f\n", ox, oy, angle*180/M_PI); + // cam: + // Compensate for distance. There must be fewer than 0.75*768 pixels between the spots for this to work. + // In other words, you have to be far enough away from the sensor bar for the two spots to have enough + // space on the image sensor to travel without one of the points going off the image. + // note: it is working very well ... + double gain = 4; + if (d < (0.75 * kWiiIRPixelsHeight)) + gain = 1 / (1 - d/kWiiIRPixelsHeight); + + ox *= gain; + oy *= gain; + + wiiremote->angle = atan2(dy, dx); wiiremote->tracking = true; } else { - // printf("Not tracking.\n"); ox = oy = -100; + wiiremote->leftPoint = -1; // not tracking wiiremote->angle = -100; - wiiremote->leftPoint = -1; wiiremote->tracking = false; } - + wiiremote->posX = ox; wiiremote->posY = oy; } +void handleButtonReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + // wiimote buttons + wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; + + // report contains extension data + switch (dp[1]) + { + case 0x34 : + case 0x35 : + case 0x36 : + case 0x37 : + handleExtensionData(wiiremote, dp, dataLength); + break; + } + + // report contains IR data + if (dp[1] & 0x02) + { + handleIRData(wiiremote, dp, dataLength); + } + + // report contains motion sensor data + if (dp[1] & 0x01) + { + wiiremote->accX = dp[4]; + wiiremote->accY = dp[5]; + wiiremote->accZ = dp[6]; + + wiiremote->lowZ = wiiremote->lowZ * 0.9 + wiiremote->accZ * 0.1; + wiiremote->lowX = wiiremote->lowX * 0.9 + wiiremote->accX * 0.1; + + float absx = abs(wiiremote->lowX-128); + float absz = abs(wiiremote->lowZ-128); + + if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; + if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; + + if (absz >= absx) + { + if (absz > 5) + wiiremote->orientation = (wiiremote->lowZ > 128)?0:2; + } + else + { + if (absx > 5) + wiiremote->orientation = (wiiremote->lowX > 128)?3:1; + } + } +} + +//-------------------------------------------------------------------------------------------- + + void myDataListener(IOBluetoothL2CAPChannelRef channel, void *dataPointer, UInt16 dataLength, void *refCon) +{ + WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; + unsigned char* dp = (unsigned char*)dataPointer; + + if (!wiiremote->device) + return; + + //controller status (expansion port and battery level data) - received when report 0x15 sent to Wiimote (getCurrentStatus:) or status of expansion port changes. + if (dp[1] == 0x20 && dataLength >= 8) + { + handleStatusReport(wiiremote, dp, dataLength); + requestUpdates(wiiremote); // Make sure we keep getting state change reports. + return; + } + + if (dp[1] == 0x21) + { + handleRAMData(wiiremote, dp, dataLength); + return; + } + + if (dp[1] == 0x22) + { // Write data response + //NSLog(@"Write data response: %00x %00x %00x %00x", dp[2], dp[3], dp[4], dp[5]); + return; + } + + // report contains button info + if ((dp[1] & 0xF0) == 0x30) + { + handleButtonReport(wiiremote, dp, dataLength); + } +} + void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) { if (event->eventType == kIOBluetoothL2CAPChannelEventTypeData) @@ -277,7 +751,34 @@ void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoo void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) { - //wiiremote_disconnect(); + CFStringRef itsAddress, myAddress; + + itsAddress = IOBluetoothDeviceGetAddressString(objectRef); + if (itsAddress != nil) + { + myAddress = IOBluetoothDeviceGetAddressString(((WiiRemoteRef)refCon)->device); + if (myAddress != nil) + { + if (CFStringCompare(itsAddress, myAddress, 0) == kCFCompareEqualTo) + { + wiiremote_disconnect((WiiRemoteRef)refCon); + } + CFRelease(myAddress); + } + CFRelease(itsAddress); + } +} + +//-------------------------------------------------------------------------------------------- + +void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address) +{ + CFStringRef cfstring; + + cfstring = IOBluetoothDeviceGetAddressString(wiiremote->device); + CFStringGetCString(cfstring, address, 32, kCFStringEncodingMacRoman); + CFRelease(cfstring); + } //-------------------------------------------------------------------------------------------- @@ -285,6 +786,7 @@ void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOB Boolean wiiremote_connect(WiiRemoteRef wiiremote) { IOReturn ret; + Boolean result; short i; if (wiiremote->device == nil) @@ -296,12 +798,12 @@ Boolean wiiremote_connect(WiiRemoteRef wiiremote) ret = IOBluetoothDeviceOpenConnection(wiiremote->device, nil, nil); if ( ret == kIOReturnSuccess) break; - usleep(10000); // wait 10ms + usleep(kWait); // wait 10ms } if (i==kTrial) return false; - wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, 0); + wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, (void *)wiiremote); // performs an SDP query for (i=0; idevice, nil, nil); if ( ret == kIOReturnSuccess) break; - usleep(10000); // wait 10ms + usleep(kWait); // wait 10ms } if (i==kTrial) return false; + + result = openCChan(wiiremote); + result = openIChan(wiiremote); - // open L2CAPChannel : BluetoothL2CAPPSM = 17 - for (i=0; idevice, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); - if ( ret == kIOReturnSuccess) - break; - usleep(10000); // wait 10ms - } - if (i==kTrial) + if (result) { - wiiremote->cchan = nil; - IOBluetoothDeviceCloseConnection(wiiremote->device); - wiiremote->device = nil; - return false; + result = wiiremote_led(wiiremote, wiiremote->isLED1Illuminated, wiiremote->isLED2Illuminated, wiiremote->isLED3Illuminated, wiiremote->isLED4Illuminated); } - // open L2CAPChannel : BluetoothL2CAPPSM = 19 - for (i=0; idevice, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); - if ( ret == kIOReturnSuccess) - break; - usleep(10000); // wait 10ms + wiiremote_disconnect(wiiremote); + return result; } - if (i==kTrial) - { - wiiremote->ichan = nil; - IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); - IOBluetoothDeviceCloseConnection(wiiremote->device); - wiiremote->device = nil; - return false; - } - - wiiremote_motionsensor(wiiremote, true); - wiiremote_irsensor(wiiremote, false); - wiiremote_vibration(wiiremote, false); - wiiremote_led(wiiremote, false, false, false, false); + + wiiremote_getstatus(wiiremote); + requestUpdates(wiiremote); + + readData(wiiremote, 0x0020, 7); // Get Accelerometer callibration data return true; } @@ -358,56 +841,58 @@ Boolean wiiremote_connect(WiiRemoteRef wiiremote) Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) { - short i; - - if (wiiremote->disconnectNotification != nil) - { - IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); - wiiremote->disconnectNotification = nil; - } - - if (wiiremote->cchan && IOBluetoothDeviceIsConnected(wiiremote->device)) + short i; + + if (wiiremote->cchan) { - for (i=0; idevice)) { - if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan) == kIOReturnSuccess) + for (i=0; icchan = nil; - break; + if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan) == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms } } if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->cchan); + wiiremote->cchan = nil; } - if (wiiremote->ichan && IOBluetoothDeviceIsConnected(wiiremote->device)) + if (wiiremote->ichan) { - for (i=0; idevice)) { - if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->ichan) == kIOReturnSuccess) + for (i=0; iichan = nil; - break; + if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->ichan) == kIOReturnSuccess) + break; } } if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->ichan); + wiiremote->ichan = nil; } - if (wiiremote->device && IOBluetoothDeviceIsConnected(wiiremote->device)) + if (wiiremote->device) { - for (i=0; idevice)) { - if (IOBluetoothDeviceCloseConnection(wiiremote->device) == kIOReturnSuccess) + for (i=0; idevice) == kIOReturnSuccess) + break; } } if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->device); + wiiremote->device = nil; } - if (wiiremote->device != nil) + if (wiiremote->disconnectNotification != nil) { - IOBluetoothObjectRelease(wiiremote->device); - wiiremote->device = nil; + IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); + wiiremote->disconnectNotification = nil; } return true; @@ -416,53 +901,77 @@ Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- -Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, size_t length) -{ - unsigned char buf[40]; - IOReturn ret; - int i; +Boolean requestUpdates(WiiRemoteRef wiiremote) +{ + Boolean result; - memset(buf,0,40); - buf[0] = 0x52; - memcpy(buf+1, data, length); - if (buf[1] == 0x16) - length=23; - else - length++; + // Set the report type the Wiimote should send. + unsigned char cmd[] = {0x12, 0x02, 0x30}; // Just buttons. - for (i = 0; icchan, buf, length); - if (ret == kIOReturnSuccess) - break; - usleep(10000); - } + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - return (ret==kIOReturnSuccess); -} - -Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, size_t length) -{ - unsigned char cmd[22]; - unsigned int i; - - for(i=0 ; iisIRSensorEnabled) + { + if (wiiremote->isExpansionPortEnabled) + { + cmd[2] = 0x36; // Buttons, 10 IR Bytes, 9 Extension Bytes + wiiremote->wiiIRMode = kWiiIRModeBasic; + } + else + { + cmd[2] = 0x33; // Buttons, Accelerometer, and 12 IR Bytes. + wiiremote->wiiIRMode = kWiiIRModeExtended; + } + + // Set IR Mode + writeData(wiiremote, (darr){ wiiremote->wiiIRMode }, 0x04B00033, 1); + usleep(kWait); // wait 10ms + } + else + { + if (wiiremote->isExpansionPortEnabled) + { + cmd[2] = 0x34; // Buttons, 19 Extension Bytes + } + else + { + cmd[2] = 0x30; // Buttons + } + } - cmd[0] = 0x16; - cmd[1] = (address>>24) & 0xFF; - cmd[2] = (address>>16) & 0xFF; - cmd[3] = (address>> 8) & 0xFF; - cmd[4] = (address>> 0) & 0xFF; - cmd[5] = length; - - // and of course the vibration flag, as usual - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; // Add Accelerometer - data = cmd; + usleep(kWait); // wait 10ms + result = sendCommand(wiiremote, cmd, 3); - return sendCommand(wiiremote, cmd, 22); + return(result); } //-------------------------------------------------------------------------------------------- @@ -470,74 +979,14 @@ Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned lo Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled) { wiiremote->isMotionSensorEnabled = enabled; - - unsigned char cmd[] = {0x12, 0x00, 0x30}; - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; - if (wiiremote->isIRSensorEnabled) cmd[2] |= 0x02; - - return sendCommand(wiiremote, cmd, 3); -} - -Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) -{ - IOReturn ret; - - wiiremote->isIRSensorEnabled = enabled; - - // set register 0x12 (report type) - if (ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled) == false) return ret; - - // set register 0x13 (ir enable/vibe) - if (ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled) == false) return ret; - - // set register 0x1a (ir enable 2) - unsigned char cmd[] = {0x1a, 0x00}; - if (enabled) cmd[1] |= 0x04; - if (ret = sendCommand(wiiremote, cmd, 2) == false) return ret; - - if(enabled){ - // based on marcan's method, found on wiili wiki: - // tweaked to include some aspects of cliff's setup procedure in the hopes - // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) - // the sleeps help it it seems - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x90}, 0x04B00006, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0xC0}, 0x04B00008, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x40}, 0x04B0001A, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x33}, 0x04B00033, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1) == false) return ret; - - }else{ - // probably should do some writes to power down the camera, save battery - // but don't know how yet. - - //bug fix #1614587 - wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); - wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); - } - - return true; + return requestUpdates(wiiremote); } Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled) { wiiremote->isVibrationEnabled = enabled; - - unsigned char cmd[] = {0x13, 0x00}; - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; - - return sendCommand(wiiremote, cmd, 2);; + return requestUpdates(wiiremote); } Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) @@ -557,6 +1006,73 @@ Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2 return sendCommand(wiiremote, cmd, 2); } +Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled) +{ + wiiremote->isExpansionPortEnabled = enabled; + if (wiiremote->isExpansionPortAttached == false) + { + wiiremote->isExpansionPortEnabled = false; + } + else + { + readData(wiiremote, 0x04A40020, 16); //get calbdata + } + + return requestUpdates(wiiremote); +} + +Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) +{ + Boolean ret; + + wiiremote->isIRSensorEnabled = enabled; + + // ir enable 1 + unsigned char cmd[] = {0x13, 0x00}; + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; + if ((ret = sendCommand(wiiremote, cmd, 2)) == false) + return ret; + usleep(kWait); + + // set register 0x1a (ir enable 2) + unsigned char cmd2[] = {0x1a, 0x00}; + if (enabled) cmd2[1] |= 0x04; + if ((ret = sendCommand(wiiremote, cmd2, 2)) == false) + return ret; + usleep(kWait); + + if(enabled) + { + // based on marcan's method, found on wiili wiki: + // tweaked to include some aspects of cliff's setup procedure in the hopes + // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) + // the sleeps help it it seems + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xC0}, 0x04B00000, 9)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x40, 0x00}, 0x04B0001A, 2)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1)) == false) return ret; + usleep(kWait); + + requestUpdates(wiiremote); + } + else + { + // probably should do some writes to power down the camera, save battery + // but don't know how yet. + + ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); + ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); + ret = wiiremote_expansion(wiiremote, wiiremote->isExpansionPortEnabled); + } + + return ret; +} + Boolean wiiremote_getstatus(WiiRemoteRef wiiremote) { unsigned char cmd[] = {0x15, 0x00}; diff --git a/wiiremote/wiiremote.h b/wiiremote/wiiremote.h index 66ec4ac..f8ad39d 100644 --- a/wiiremote/wiiremote.h +++ b/wiiremote/wiiremote.h @@ -8,16 +8,96 @@ #include #include +// Macros for PD for compability with Max macros +#ifdef PD +#define SETSYM SETSYMBOL +#define SETLONG SETFLOAT +#endif + +typedef unsigned char WiiIRModeType; +enum { + kWiiIRModeBasic = 0x01, + kWiiIRModeExtended = 0x03, + kWiiIRModeFull = 0x05 +}; + typedef struct { int x, y, s; } IRData; +typedef struct { + unsigned char accX_zero, accY_zero, accZ_zero, accX_1g, accY_1g, accZ_1g; +} WiiAccCalibData; + +typedef struct { + unsigned char x_min, x_max, x_center, y_min, y_max, y_center; +} WiiJoyStickCalibData; + +typedef UInt16 WiiButtonType; +enum { + WiiRemoteAButton, + WiiRemoteBButton, + WiiRemoteOneButton, + WiiRemoteTwoButton, + WiiRemoteMinusButton, + WiiRemoteHomeButton, + WiiRemotePlusButton, + WiiRemoteUpButton, + WiiRemoteDownButton, + WiiRemoteLeftButton, + WiiRemoteRightButton, + + WiiNunchukZButton, + WiiNunchukCButton, + + WiiClassicControllerXButton, + WiiClassicControllerYButton, + WiiClassicControllerAButton, + WiiClassicControllerBButton, + WiiClassicControllerLButton, + WiiClassicControllerRButton, + WiiClassicControllerZLButton, + WiiClassicControllerZRButton, + WiiClassicControllerUpButton, + WiiClassicControllerDownButton, + WiiClassicControllerLeftButton, + WiiClassicControllerRightButton, + WiiClassicControllerMinusButton, + WiiClassicControllerHomeButton, + WiiClassicControllerPlusButton +}; + + +typedef UInt16 WiiExpansionPortType; +enum{ + WiiExpNotAttached, + WiiNunchuk, + WiiClassicController +}; + +typedef UInt16 WiiAccelerationSensorType; +enum{ + WiiRemoteAccelerationSensor, + WiiNunchukAccelerationSensor +}; + + +typedef UInt16 WiiJoyStickType; +enum{ + WiiNunchukJoyStick, + WiiClassicControllerLeftJoyStick, + WiiClassicControllerRightJoyStick +}; + + typedef struct _WiiRemoteRec { IOBluetoothDeviceInquiryRef inquiry; IOBluetoothDeviceRef device; IOBluetoothL2CAPChannelRef ichan; IOBluetoothL2CAPChannelRef cchan; + + CFStringRef address; unsigned char accX; unsigned char accY; @@ -28,35 +108,68 @@ typedef struct _WiiRemoteRec float lowX; int orientation; int leftPoint; // is point 0 or 1 on the left. -1 when not tracking. + float posX; float posY; float angle; Boolean tracking; - + + WiiExpansionPortType expType; + WiiAccCalibData wiiCalibData, nunchukCalibData; + WiiJoyStickCalibData nunchukJoyStickCalibData; + WiiIRModeType wiiIRMode; IRData irData[4]; double batteryLevel; - Boolean isIRSensorEnabled; + Boolean readingRegister; Boolean isMotionSensorEnabled; + Boolean isIRSensorEnabled; Boolean isVibrationEnabled; - - Boolean isExpansionPortUsed; + Boolean isExpansionPortEnabled; + Boolean initExpPort; Boolean isLED1Illuminated; Boolean isLED2Illuminated; Boolean isLED3Illuminated; Boolean isLED4Illuminated; + Boolean isExpansionPortAttached; + IOBluetoothUserNotificationRef disconnectNotification; + + //nunchuk + unsigned char nStickX; + unsigned char nStickY; + unsigned char nAccX; + unsigned char nAccY; + unsigned char nAccZ; + unsigned char nButtonData; + + float nLowZ; + float nLowX; + int nOrientation; + + //classic controller + unsigned short cButtonData; + unsigned char cStickX1; + unsigned char cStickY1; + unsigned char cStickX2; + unsigned char cStickY2; + unsigned char cAnalogL; + unsigned char cAnalogR; + } WiiRemoteRec, *WiiRemoteRef; void wiiremote_init(WiiRemoteRef wiiremote); Boolean wiiremote_isconnected(WiiRemoteRef wiiremote); -Boolean wiiremote_search(WiiRemoteRef wiiremote); +Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address); Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote); Boolean wiiremote_connect(WiiRemoteRef wiiremote); Boolean wiiremote_disconnect(WiiRemoteRef wiiremote); +void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address); Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); +Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_getstatus(WiiRemoteRef wiiremote); + -- cgit v1.2.1