diff options
-rw-r--r-- | wiiremote/COPYRIGHT.txt | 13 | ||||
-rw-r--r-- | wiiremote/Makefile | 32 | ||||
-rw-r--r-- | wiiremote/aka.wiiremote.c | 362 | ||||
-rw-r--r-- | wiiremote/wiiremote.c | 543 | ||||
-rw-r--r-- | wiiremote/wiiremote.h | 62 |
5 files changed, 1012 insertions, 0 deletions
diff --git a/wiiremote/COPYRIGHT.txt b/wiiremote/COPYRIGHT.txt new file mode 100644 index 0000000..b33233c --- /dev/null +++ b/wiiremote/COPYRIGHT.txt @@ -0,0 +1,13 @@ +Max porting by Masayuki Akamatsu +Copyright (c) 2006, Masayuki Akamatsu +Based on "DarwiinRemote" by Hiroaki Kimura +Copyright (c) 2006, Hiroaki Kimura +All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/wiiremote/Makefile b/wiiremote/Makefile new file mode 100644 index 0000000..78d1860 --- /dev/null +++ b/wiiremote/Makefile @@ -0,0 +1,32 @@ +TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') +EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') + +default: + make -C $(EXTERNALS_ROOT) $(TARGET) + +install: + make -C $(EXTERNALS_ROOT) $(TARGET)_install + +clean: + make -C $(EXTERNALS_ROOT) $(TARGET)_clean + +test_locations: + make -C $(EXTERNALS_ROOT) test_locations + +# for emacs +etags: + etags ../../../pd/src/*.h *.[ch] linux/input.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] + +etags_Linux: + etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: + etags -a /usr/include/*.h /usr/include/sys/*.h \ + /usr/local/include/*.h /usr/local/include/sys/*.h diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c new file mode 100644 index 0000000..4ec6ad0 --- /dev/null +++ b/wiiremote/aka.wiiremote.c @@ -0,0 +1,362 @@ +// aka.wiiremote.c +// Copyright by Masayuki Akamatsu +// port to Pd by Hans-Christoph Steiner <hans@at.or.at> + + +#ifdef PD +#include "m_pd.h" +#define SETLONG SETFLOAT +static t_class *wiiremote_class; +#else /* Max */ +#include "ext.h" +#endif +#include "wiiremote.h" + +#define kInterval 100 +#define kMaxTrial 100 + + +typedef struct _akawiiremote +{ +#ifdef PD + t_object x_obj; +#else /* Max */ + struct object obj; +#endif + + WiiRemoteRef wiiremote; + + void *clock; + long interval; + long trial; + + void *statusOut; + void *buttonsOut; + void *irOut; + void *accOut; +} t_akawiiremote; + +void *akawiiremote_class; // the number of instance of this object + +short akawiiremote_count; + +void akawiiremote_bang(t_akawiiremote *x); +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_getbatterylevel(t_akawiiremote *x); +void akawiiremote_getexpansionstatus(t_akawiiremote *x); +void akawiiremote_getledstatus(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); + +#ifdef PD +void wiiremote_setup() +{ + wiiremote_class = class_new(gensym("wiiremote"), + (t_newmethod)akawiiremote_new, + (t_method)akawiiremote_free, + sizeof(t_akawiiremote), + CLASS_DEFAULT, + A_GIMME,0); + + 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_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_assist,gensym("assist"),A_CANT,0); + + post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); + post("\tPd port by Hans-Christoph Steiner"); + + akawiiremote_count = 0; +} +#else /* Max */ +void main() +{ + 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_disconnect,"disconnect",0); + addmess((method)akawiiremote_motionsensor,"motionsensor", A_DEFLONG, 0); + addmess((method)akawiiremote_irsensor,"irsensor", 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_assist,"assist",A_CANT,0); + + post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); + + akawiiremote_count = 0; +} +#endif /* PD */ +//-------------------------------------------------------------------------------------------- + +void akawiiremote_bang(t_akawiiremote *x) +{ + t_atom list[4]; + + if (x->wiiremote->device == nil) + return; // do nothing + +#ifdef PD + outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); + + if (x->wiiremote->isIRSensorEnabled) + { + SETFLOAT(list, x->wiiremote->posX); + SETFLOAT(list + 1, x->wiiremote->posY); + SETFLOAT(list + 2, x->wiiremote->angle); + SETFLOAT (list + 3, x->wiiremote->tracking); + outlet_list(x->irOut, &s_list, 4, list); + } + + if (x->wiiremote->isMotionSensorEnabled) + { + SETFLOAT(list, x->wiiremote->accX); + SETFLOAT(list + 1, x->wiiremote->accY); + SETFLOAT(list + 2, x->wiiremote->accZ); + SETFLOAT(list + 3, x->wiiremote->orientation); + outlet_list(x->accOut, &s_list, 4, list); + } +#else /* Max */ + outlet_int(x->buttonsOut, x->wiiremote->buttonData); + + 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); + } + + 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); + } +#endif /* PD */ + + wiiremote_getstatus(); +} + +void akawiiremote_connect(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) // if not connected + { + if (x->wiiremote->inquiry == nil) // if not seatching + { + Boolean result; + + result = wiiremote_search(); // start searching the device + x->trial = 0; + clock_delay(x->clock, 0); // start clock to check the device found + } + } + else // if already connected + { + t_atom status; + + SETLONG(&status, 1); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } +} + +void akawiiremote_disconnect(t_akawiiremote *x) +{ + Boolean result; + t_atom status; + + result = wiiremote_disconnect(); + SETLONG(&status, result); + outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); +} + +void akawiiremote_motionsensor(t_akawiiremote *x, long enable) +{ + wiiremote_motionsensor(enable); +} + +void akawiiremote_irsensor(t_akawiiremote *x, long enable) +{ + wiiremote_irsensor(enable); +} + +void akawiiremote_vibration(t_akawiiremote *x, long enable) +{ + wiiremote_vibration(enable); +} + +void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) +{ + wiiremote_led(enable1, enable2, enable3, enable4); +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_getbatterylevel(t_akawiiremote *x) +{ + t_atom status; + + SETFLOAT(&status, x->wiiremote->batteryLevel); + outlet_anything(x->statusOut, gensym("batterylevel"), 1, &status); +} + +void akawiiremote_getexpansionstatus(t_akawiiremote *x) +{ + t_atom status; + + SETLONG(&status, x->wiiremote->isExpansionPortUsed); + outlet_anything(x->statusOut, gensym("expansionstatus"), 1, &status); +} + +void akawiiremote_getledstatus(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); +#ifdef PD + outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); +#else /* Max */ + outlet_anything(x->statusOut, gensym("ledstatus"), 4, &list); +#endif +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_clock(t_akawiiremote *x) +{ + Boolean result; + t_atom status; + + if (x->wiiremote->device != nil) // if the device is found... + { + clock_unset(x->clock); // stop clock + + wiiremote_stopsearch(); + result = wiiremote_connect(); // connect to it + SETLONG(&status, result); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } + else // if the device is not found... + { + 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(); + 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 + } + } +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) +{ +#ifndef PD /* Max */ + if (m==ASSIST_INLET) + { + sprintf(s,"connect, bang, disconnect...."); + } + else +#endif /* NOT PD */ + { + 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; + } + } +} + +//-------------------------------------------------------------------------------------------- + +void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) +{ +#ifdef PD + t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); + + 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; + + x = (t_akawiiremote *)newobject(akawiiremote_class); + + x->wiiremote = wiiremote_init(); + + x->clock = clock_new(x, (method)akawiiremote_clock); + + x->statusOut = outlet_new(x, 0); + x->buttonsOut = intout(x); + x->irOut = listout(x); + x->accOut = listout(x); +#endif /* PD */ + x->trial = 0; + x->interval = kInterval; + + + akawiiremote_count++; + return x; +} + +void akawiiremote_free(t_akawiiremote *x) +{ + akawiiremote_count--; + if (akawiiremote_count == 0) + wiiremote_disconnect(); + +#ifdef PD + if (x->clock) + clock_unset(x->clock); + clock_free(x->clock); +#else /* Max */ + freeobject(x->clock); +#endif +} + diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c new file mode 100644 index 0000000..13b1ea6 --- /dev/null +++ b/wiiremote/wiiremote.c @@ -0,0 +1,543 @@ +// wiiremote.c +// Copyright by Masayuki Akamatsu +// Based on "DarwiinRemote" by Hiroaki Kimura + +#include "wiiremote.h" + +// this type is used a lot (data array): +typedef unsigned char darr[]; + +#define kTrial 10 + +static WiiRemoteRec gWiiRemote; + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +WiiRemoteRef wiiremote_init(void) +{ + gWiiRemote.inquiry = nil; + gWiiRemote.device = nil; + gWiiRemote.ichan = nil; + gWiiRemote.cchan = nil; + + gWiiRemote.accX = 0x10; + gWiiRemote.accY = 0x10; + gWiiRemote.accZ = 0x10; + gWiiRemote.buttonData = 0; + gWiiRemote.leftPoint = -1; + gWiiRemote.tracking = false; + + gWiiRemote.batteryLevel = 0; + + gWiiRemote.isIRSensorEnabled = false; + gWiiRemote.isMotionSensorEnabled = false; + gWiiRemote.isVibrationEnabled = false; + + gWiiRemote.isExpansionPortUsed = false; + gWiiRemote.isLED1Illuminated = false; + gWiiRemote.isLED2Illuminated = false; + gWiiRemote.isLED3Illuminated = false; + gWiiRemote.isLED4Illuminated = false; + + return &gWiiRemote; +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +void checkDevice(IOBluetoothDeviceRef device) +{ + CFStringRef myString; + + myString = IOBluetoothDeviceGetName(device); + if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) + { + gWiiRemote.device = IOBluetoothObjectRetain(device); + } +} + +IOBluetoothDeviceInquiryDeviceFoundCallback myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) +{ + checkDevice(device); +} + +IOBluetoothDeviceInquiryDeviceNameUpdatedCallback myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) +{ + checkDevice(device); +} + +IOBluetoothDeviceInquiryCompleteCallback myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) +{ + IOReturn result; + + if (aborted) return; // called by stop ;) + + if (error != kIOReturnSuccess) + { + wiiremote_stopsearch(); + return; + } +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_search(void) +{ + IOReturn ret; + + if (gWiiRemote.inquiry != nil) + return true; + + gWiiRemote.inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon(nil); + IOBluetoothDeviceInquirySetDeviceFoundCallback(gWiiRemote.inquiry, myFoundFunc); + IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(gWiiRemote.inquiry, myUpdatedFunc); + IOBluetoothDeviceInquirySetCompleteCallback(gWiiRemote.inquiry, myCompleteFunc); + + ret = IOBluetoothDeviceInquiryStart(gWiiRemote.inquiry); + if (ret != kIOReturnSuccess) + { + IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry); + gWiiRemote.inquiry = nil; + return false; + } + return true; +} + +Boolean wiiremote_stopsearch(void) +{ + IOReturn ret; + + if (gWiiRemote.inquiry == nil) + { + return true; // already stopped + } + + ret = IOBluetoothDeviceInquiryStop(gWiiRemote.inquiry); + + if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted) + { + // kIOReturnNotPermitted is if it's already stopped + } + + IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry); + gWiiRemote.inquiry = nil; + + return (ret==kIOReturnSuccess); +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + + IOBluetoothL2CAPChannelIncomingDataListener myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon) +{ + unsigned char *dp = (unsigned char*)data; + + if (dp[1] == 0x20 && length >= 8) + { + gWiiRemote.batteryLevel = (double)dp[7]; + gWiiRemote.batteryLevel /= (double)0xC0; + + gWiiRemote.isExpansionPortUsed = (dp[4] & 0x02) != 0; + gWiiRemote.isLED1Illuminated = (dp[4] & 0x10) != 0; + gWiiRemote.isLED2Illuminated = (dp[4] & 0x20) != 0; + gWiiRemote.isLED3Illuminated = (dp[4] & 0x40) != 0; + gWiiRemote.isLED4Illuminated = (dp[4] & 0x80) != 0; + + //have to reset settings (vibration, motion, IR and so on...) + wiiremote_irsensor(gWiiRemote.isIRSensorEnabled); + } + + if ((dp[1]&0xF0) == 0x30) + { + gWiiRemote.buttonData = ((short)dp[2] << 8) + dp[3]; + + if (dp[1] & 0x01) + { + gWiiRemote.accX = dp[4]; + gWiiRemote.accY = dp[5]; + gWiiRemote.accZ = dp[6]; + + gWiiRemote.lowZ = gWiiRemote.lowZ * .9 + gWiiRemote.accZ * .1; + gWiiRemote.lowX = gWiiRemote.lowX * .9 + gWiiRemote.accX * .1; + + float absx = abs(gWiiRemote.lowX - 128); + float absz = abs(gWiiRemote.lowZ - 128); + + if (gWiiRemote.orientation == 0 || gWiiRemote.orientation == 2) absx -= 5; + if (gWiiRemote.orientation == 1 || gWiiRemote.orientation == 3) absz -= 5; + + if (absz >= absx) + { + if (absz > 5) + gWiiRemote.orientation = (gWiiRemote.lowZ > 128) ? 0 : 2; + } + else + { + if (absx > 5) + gWiiRemote.orientation = (gWiiRemote.lowX > 128) ? 3 : 1; + } + //printf("orientation: %d\n", orientation); + } + + if (dp[1] & 0x02) + { + int i; + for(i=0 ; i<4 ; i++) + { + gWiiRemote.irData[i].x = dp[7 + 3*i]; + gWiiRemote.irData[i].y = dp[8 + 3*i]; + gWiiRemote.irData[i].s = dp[9 + 3*i]; + gWiiRemote.irData[i].x += (gWiiRemote.irData[i].s & 0x30) << 4; + gWiiRemote.irData[i].y += (gWiiRemote.irData[i].s & 0xC0) << 2; + gWiiRemote.irData[i].s &= 0x0F; + } + } + } + + float ox, oy; + + if (gWiiRemote.irData[0].s < 0x0F && gWiiRemote.irData[1].s < 0x0F) + { + int l = gWiiRemote.leftPoint, r; + if (gWiiRemote.leftPoint == -1) + { + // printf("Tracking.\n"); + switch (gWiiRemote.orientation) + { + case 0: l = (gWiiRemote.irData[0].x < gWiiRemote.irData[1].x) ? 0 : 1; break; + case 1: l = (gWiiRemote.irData[0].y > gWiiRemote.irData[1].y) ? 0 : 1; break; + case 2: l = (gWiiRemote.irData[0].x > gWiiRemote.irData[1].x) ? 0 : 1; break; + case 3: l = (gWiiRemote.irData[0].y < gWiiRemote.irData[1].y) ? 0 : 1; break; + } + gWiiRemote.leftPoint = l; + } + + r = 1-l; + + float dx = gWiiRemote.irData[r].x - gWiiRemote.irData[l].x; + float dy = gWiiRemote.irData[r].y - gWiiRemote.irData[l].y; + + float d = sqrt(dx*dx+dy*dy); + + dx /= d; + dy /= d; + + float cx = (gWiiRemote.irData[l].x+gWiiRemote.irData[r].x)/1024.0 - 1; + float cy = (gWiiRemote.irData[l].y+gWiiRemote.irData[r].y)/1024.0 - .75; + + gWiiRemote.angle = atan2(dy, dx); + + 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); + + gWiiRemote.tracking = true; + } + else + { + // printf("Not tracking.\n"); + ox = oy = -100; + gWiiRemote.leftPoint = -1; + gWiiRemote.tracking = false; + } + + gWiiRemote.posX = ox; + gWiiRemote.posY = oy; +} + +IOBluetoothL2CAPChannelIncomingEventListener myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) +{ + switch (event->eventType) + { + case kIOBluetoothL2CAPChannelEventTypeData: + // In thise case: + // event->u.newData.dataPtr is a pointer to the block of data received. + // event->u.newData.dataSize is the size of the block of data. + myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon); + break; + + case kIOBluetoothL2CAPChannelEventTypeClosed: + // In this case: + // event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel + // object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below). + break; + } +} + +IOBluetoothUserNotificationCallback myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) +{ + wiiremote_disconnect(); +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_connect(void) +{ + IOReturn result; + short i; + + if (gWiiRemote.device == nil) + return false; + + // connect the device + for (i=0; i<kTrial; i++) + { + if (IOBluetoothDeviceOpenConnection(gWiiRemote.device, nil, nil) == kIOReturnSuccess) + break; + usleep(10000); // wait 10ms + } + if (i==kTrial) return false; + + gWiiRemote.disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(gWiiRemote.device, myDisconnectedFunc, 0); + + // performs an SDP query + for (i=0; i<kTrial; i++) + { + if (IOBluetoothDevicePerformSDPQuery(gWiiRemote.device, nil, nil) == kIOReturnSuccess) + break; + usleep(10000); // wait 10ms + } + if (i==kTrial) return false; + + // open L2CAPChannel : BluetoothL2CAPPSM = 17 + for (i=0; i<kTrial; i++) + { + if (IOBluetoothDeviceOpenL2CAPChannelSync(gWiiRemote.device, &(gWiiRemote.cchan), 17, myEventListener, nil) == kIOReturnSuccess) + break; + usleep(10000); // wait 10ms + } + if (i==kTrial) + { + gWiiRemote.cchan = nil; + IOBluetoothDeviceCloseConnection(gWiiRemote.device); + return false; + } + + // open L2CAPChannel : BluetoothL2CAPPSM = 19 + for (i=0; i<kTrial; i++) + { + if (IOBluetoothDeviceOpenL2CAPChannelSync(gWiiRemote.device, &(gWiiRemote.ichan), 19, myEventListener, nil) == kIOReturnSuccess) + break; + usleep(10000); // wait 10ms + } + if (i==kTrial) + { + gWiiRemote.ichan = nil; + IOBluetoothL2CAPChannelCloseChannel(gWiiRemote.cchan); + IOBluetoothDeviceCloseConnection(gWiiRemote.device); + return false; + } + + wiiremote_motionsensor(true); + wiiremote_irsensor(false); + wiiremote_vibration(false); + wiiremote_led(false, false, false, false); + + return true; +} + + +Boolean wiiremote_disconnect(void) +{ + short i; + + if (gWiiRemote.disconnectNotification != nil) + { + IOBluetoothUserNotificationUnregister(gWiiRemote.disconnectNotification); + gWiiRemote.disconnectNotification = nil; + } + + if (gWiiRemote.cchan && IOBluetoothDeviceIsConnected(gWiiRemote.device)) + { + for (i=0; i<kTrial; i++) + { + if (IOBluetoothL2CAPChannelCloseChannel(gWiiRemote.cchan) == kIOReturnSuccess) + { + gWiiRemote.cchan = nil; + break; + } + } + if (i==kTrial) return false; + } + + if (gWiiRemote.ichan && IOBluetoothDeviceIsConnected(gWiiRemote.device)) + { + for (i=0; i<kTrial; i++) + { + if (IOBluetoothL2CAPChannelCloseChannel(gWiiRemote.ichan) == kIOReturnSuccess) + { + gWiiRemote.ichan = nil; + break; + } + } + if (i==kTrial) return false; + } + + if (gWiiRemote.device && IOBluetoothDeviceIsConnected(gWiiRemote.device)) + { + for (i=0; i<kTrial; i++) + { + if (IOBluetoothDeviceCloseConnection(gWiiRemote.device) == kIOReturnSuccess) + { + gWiiRemote.device = nil; + break; + } + } + if (i==kTrial) return false; + } + + return true; +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +Boolean sendCommand(unsigned char *data, size_t 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++; + + for (i = 0; i<kTrial; i++) + { + ret = IOBluetoothL2CAPChannelWriteSync(gWiiRemote.cchan, buf, length); + if (ret == kIOReturnSuccess) + break; + usleep(10000); + } + + return (ret==kIOReturnSuccess); +} + +Boolean writeData(const unsigned char *data, unsigned long address, size_t length) +{ + unsigned char cmd[22]; + int i; + + for(i=0 ; i<length ; i++) cmd[i+6] = data[i]; + + for(;i<16 ; i++) cmd[i+6]= 0; + + 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 (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + + data = cmd; + + return sendCommand(cmd, 22); +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_motionsensor(Boolean enabled) +{ + gWiiRemote.isMotionSensorEnabled = enabled; + + unsigned char cmd[] = {0x12, 0x00, 0x30}; + if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + if (gWiiRemote.isMotionSensorEnabled) cmd[2] |= 0x01; + if (gWiiRemote.isIRSensorEnabled) cmd[2] |= 0x02; + + return sendCommand(cmd, 3); +} + +Boolean wiiremote_irsensor(Boolean enabled) +{ + IOReturn ret; + + gWiiRemote.isIRSensorEnabled = enabled; + + // set register 0x12 (report type) + if (ret = wiiremote_motionsensor(gWiiRemote.isMotionSensorEnabled)) return ret; + + // set register 0x13 (ir enable/vibe) + if (ret = wiiremote_vibration(gWiiRemote.isVibrationEnabled)) return ret; + + // set register 0x1a (ir enable 2) + unsigned char cmd[] = {0x1a, 0x00}; + if (enabled) cmd[1] |= 0x04; + if (ret = sendCommand(cmd, 2)) 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((darr){0x01}, 0x04B00030, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x08}, 0x04B00030, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x90}, 0x04B00006, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0xC0}, 0x04B00008, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x40}, 0x04B0001A, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x33}, 0x04B00033, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x08}, 0x04B00030, 1)) 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(gWiiRemote.isMotionSensorEnabled); + wiiremote_vibration(gWiiRemote.isVibrationEnabled); + } + + return true; +} + +Boolean wiiremote_vibration(Boolean enabled) +{ + + gWiiRemote.isVibrationEnabled = enabled; + + unsigned char cmd[] = {0x13, 0x00}; + if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + if (gWiiRemote.isIRSensorEnabled) cmd[1] |= 0x04; + + return sendCommand(cmd, 2);; +} + +Boolean wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) +{ + unsigned char cmd[] = {0x11, 0x00}; + if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + if (enabled1) cmd[1] |= 0x10; + if (enabled2) cmd[1] |= 0x20; + if (enabled3) cmd[1] |= 0x40; + if (enabled4) cmd[1] |= 0x80; + + gWiiRemote.isLED1Illuminated = enabled1; + gWiiRemote.isLED2Illuminated = enabled2; + gWiiRemote.isLED3Illuminated = enabled3; + gWiiRemote.isLED4Illuminated = enabled4; + + return sendCommand(cmd, 2); +} + +void wiiremote_getstatus(void) +{ + unsigned char cmd[] = {0x15, 0x00}; + sendCommand(cmd, 2); +} + + diff --git a/wiiremote/wiiremote.h b/wiiremote/wiiremote.h new file mode 100644 index 0000000..1e8cb00 --- /dev/null +++ b/wiiremote/wiiremote.h @@ -0,0 +1,62 @@ +// wiiremote.h +// Copyright by Masayuki Akamatsu +// Based on "DarwiinRemote" by Hiroaki Kimura + +#include <CoreFoundation/CoreFoundation.h> +#include <IOBluetooth/Bluetooth.h> +#include <IOBluetooth/IOBluetoothUserLib.h> + +#include <stdio.h> +#include <string.h> + +typedef struct { + int x, y, s; +} IRData; + +typedef struct _WiiRemoteRec +{ + IOBluetoothDeviceInquiryRef inquiry; + IOBluetoothDeviceRef device; + IOBluetoothL2CAPChannelRef ichan; + IOBluetoothL2CAPChannelRef cchan; + + unsigned char accX; + unsigned char accY; + unsigned char accZ; + unsigned short buttonData; + + float lowZ; + 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; + + IRData irData[4]; + double batteryLevel; + + Boolean isIRSensorEnabled; + Boolean isMotionSensorEnabled; + Boolean isVibrationEnabled; + + Boolean isExpansionPortUsed; + Boolean isLED1Illuminated; + Boolean isLED2Illuminated; + Boolean isLED3Illuminated; + Boolean isLED4Illuminated; + + IOBluetoothUserNotificationCallback *disconnectNotification; +} WiiRemoteRec, *WiiRemoteRef; + +WiiRemoteRef wiiremote_init(void); +Boolean wiiremote_search(void); +Boolean wiiremote_stopsearch(void); +Boolean wiiremote_connect(void); +Boolean wiiremote_disconnect(void); +Boolean wiiremote_motionsensor(Boolean enabled); +Boolean wiiremote_irsensor(Boolean enabled); +Boolean wiiremote_vibration(Boolean enabled); +Boolean wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); +void wiiremote_getstatus(void); |