aboutsummaryrefslogtreecommitdiff
path: root/aka.wiiremote
diff options
context:
space:
mode:
authorHans-Christoph Steiner <eighthave@users.sourceforge.net>2008-03-10 21:50:43 +0000
committerIOhannes m zmölnig <zmoelnig@iem.at>2015-10-14 15:08:25 +0200
commitda3f6b1d47080e0162944834d18017c9a691c0b1 (patch)
tree7a694aa59e70926112eca729716fbcaa655b6508 /aka.wiiremote
parent71d377c64cf05eb5726e4ec803dc8288bf4c8357 (diff)
moved wiiremote to aka.wiiremote to reflect the name of the Max/MSP object.
This is a direct port, so it makes sense to have the same name. svn path=/trunk/externals/io/; revision=9551
Diffstat (limited to 'aka.wiiremote')
-rw-r--r--aka.wiiremote/COPYRIGHT.txt13
-rw-r--r--aka.wiiremote/HISTORY.txt54
-rw-r--r--aka.wiiremote/Makefile33
-rw-r--r--aka.wiiremote/README.txt6
-rw-r--r--aka.wiiremote/TODO7
-rw-r--r--aka.wiiremote/aka.wiiremote.c642
-rw-r--r--aka.wiiremote/wiiremote-help.pd80
-rw-r--r--aka.wiiremote/wiiremote.c1087
-rw-r--r--aka.wiiremote/wiiremote.h175
9 files changed, 2097 insertions, 0 deletions
diff --git a/aka.wiiremote/COPYRIGHT.txt b/aka.wiiremote/COPYRIGHT.txt
new file mode 100644
index 0000000..b33233c
--- /dev/null
+++ b/aka.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/aka.wiiremote/HISTORY.txt b/aka.wiiremote/HISTORY.txt
new file mode 100644
index 0000000..a0687b1
--- /dev/null
+++ b/aka.wiiremote/HISTORY.txt
@@ -0,0 +1,54 @@
+aka.wiiremote Version History
+
+1.0B6 : 2007.04.24
+
+- The Classic Controller is supported.
+- The help patch is updated.
+- The URLs in [info] subpatch are updated.
+
+- 'expansion' message enables to use the expansion controller(Nunchuk or Classic Controller).
+- 'nunchuk' message is obsolete.
+ You should use 'expansion' instead of it even though you can use it for the backward compatibility only.
+
+- The IR sensor and the expansion controller (ex. Nunchuk) can be used together.
+
+- The stability on PPC-Mac is a little improved.
+ You have to do the following steps every time you use the Wii Remote on PPC-Mac.
+ (You would set up only once on Intel-Mac.)
+1: Delete "Nintendo RVL-CNT-01" on "Device" tab in "Bluetooth" System Preference.
+2: Do the setup for Wii Remote. See http://max.iamas.ac.jp/2061/articles/121.html
+3: Open "aka.wiiremote.help" and connect it.
+
+
+1.0B5 : 2007.02.03
+
+- Nunchuk is supported.
+( Classic Controller is NOT supported.)
+- device address is supported.
+- outlets and output messages are changed.
+- some input messages are simplified.
+- help patch is expanded for Nunchuk.
+
+
+1.0B4 : 2006.12.24
+
+- multiple Wii remotes are supported.
+
+
+1.0B3 : 2006.12.20
+
+- data acquisition is improved.
+- unusual vibration sound is resolved.
+
+
+1.0B2 : 2006.12.15
+
+- connection/disconnection is improved.
+- IR sensor is supported.
+- status report is supported
+- help patch is rewritten.
+
+
+1.0B1 : 2006.12.12
+
+- first release \ No newline at end of file
diff --git a/aka.wiiremote/Makefile b/aka.wiiremote/Makefile
new file mode 100644
index 0000000..e222c9b
--- /dev/null
+++ b/aka.wiiremote/Makefile
@@ -0,0 +1,33 @@
+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]
+ make etags_`uname -s`
+
+etags_Darwin:
+ etags -a \
+ /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \
+ /System/Library/Frameworks/CoreFoundation.framework/Headers/*.h \
+ /System/Library/Frameworks/Carbon.framework/Headers/*.h \
+ /System/Library/Frameworks/IOBluetooth.framework/Headers/*.[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/aka.wiiremote/README.txt b/aka.wiiremote/README.txt
new file mode 100644
index 0000000..bdaf778
--- /dev/null
+++ b/aka.wiiremote/README.txt
@@ -0,0 +1,6 @@
+
+This is a port of the Max class aka.wiiremote by Masayuki Akamatsu. Its
+available here:
+
+http://www.iamas.ac.jp/~aka/max/#aka_wiiremote
+
diff --git a/aka.wiiremote/TODO b/aka.wiiremote/TODO
new file mode 100644
index 0000000..a8da43d
--- /dev/null
+++ b/aka.wiiremote/TODO
@@ -0,0 +1,7 @@
+
+
+ - try out IOBluetoothLocalDeviceAvailable(wiiremote->inquiry); to see if that will set up the event loops (http://lists.apple.com/archives/bluetooth-dev/2006/Dec/msg00001.html)
+
+
+- try CFRunLoopRun(); then CFRunLoopStop(CFRunLoopGetCurrent()); in akawiiremote_clock() and akawiiremote_bang()
+
diff --git a/aka.wiiremote/aka.wiiremote.c b/aka.wiiremote/aka.wiiremote.c
new file mode 100644
index 0000000..767d737
--- /dev/null
+++ b/aka.wiiremote/aka.wiiremote.c
@@ -0,0 +1,642 @@
+// 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
+//#define addbang(x) class_addbang(wiiremote_class, (x))
+//#define addmess(x) class_addmessage(class_wiiremote, (x))
+static t_class *wiiremote_class;
+#else /* Max */
+#include "ext.h"
+#endif /* PD */
+
+#include "wiiremote.h"
+#include <stdio.h>
+#include <string.h>
+
+#define kInterval 100
+#define kMaxTrial 100
+
+typedef struct _akawiiremote
+{
+#ifdef PD
+ t_object x_obj;
+#else /* Max */
+ struct object obj;
+#endif
+
+ WiiRemoteRef wiiremote;
+ char address[32];
+
+ void *clock;
+ Boolean connected;
+
+ void *statusOut;
+ 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_extraoutput(t_akawiiremote *x, long enable);
+
+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 */
+void main()
+#endif /* PD */
+{
+ NumVersion outSoftwareVersion;
+ BluetoothHCIVersionInfo outHardwareVersion;
+
+ post("aka.wiiremote 1.0B7-UB by Masayuki Akamatsu");
+
+ if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) // B7
+ {
+ if (outSoftwareVersion.majorRev < 1 && outSoftwareVersion.minorAndBugRev < 0x63)
+ {
+ error("requires Blutooth version 1.6.3 or later.");
+ return;
+ }
+ }
+ else
+ {
+ error("can't get Bluetooth version.");
+ return;
+ }
+
+#ifdef PD
+ post("\tPd port by Hans-Christoph Steiner");
+
+ 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_address,gensym("address"),A_DEFSYMBOL, 0);
+ 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("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_expansion,gensym("expansion"), A_DEFFLOAT, 0);
+ class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("nunchuk"), A_DEFFLOAT, 0);
+ class_addmethod(wiiremote_class,(t_method)akawiiremote_extraoutput,gensym("extraoutput"), A_DEFFLOAT, 0); // B7
+
+ 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_getaddress,gensym("getaddress"),0);
+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getcalibration,gensym("getcalibration"), 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_address,"address",A_DEFSYM, 0);
+ addmess((method)akawiiremote_connect,"connect", 0);
+ addmess((method)akawiiremote_disconnect,"disconnect",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_expansion,"expansion", A_DEFLONG, 0);
+ addmess((method)akawiiremote_expansion,"nunchuk", A_DEFLONG, 0);
+ addmess((method)akawiiremote_extraoutput,"extraoutput", A_DEFLONG, 0); // B7
+
+ 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 */
+}
+
+//--------------------------------------------------------------------------------------------
+
+void akawiiremote_bang(t_akawiiremote *x)
+{
+ t_atom av[7];
+
+ if (x->wiiremote->device == nil)
+ return; // do nothing
+
+ 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);
+
+ if (x->wiiremote->isExtraOutputEnabled)
+ {
+ SETSYM(av, gensym("stick_calibration"));
+ SETLONG(av + 1, x->wiiremote->nunchukJoyStickCalibData.x_min);
+ SETLONG(av + 2, x->wiiremote->nunchukJoyStickCalibData.x_max);
+ SETLONG(av + 3, x->wiiremote->nunchukJoyStickCalibData.x_center);
+ SETLONG(av + 4, x->wiiremote->nunchukJoyStickCalibData.y_min);
+ SETLONG(av + 5, x->wiiremote->nunchukJoyStickCalibData.y_max);
+ SETLONG(av + 6, x->wiiremote->nunchukJoyStickCalibData.y_center);
+ outlet_anything(x->dataOut, gensym(nunchukStr), 7, 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);
+
+ if (x->wiiremote->isExtraOutputEnabled)
+ {
+ SETSYM(av, gensym("motion_calibration"));
+ SETLONG(av + 1, x->wiiremote->nunchukCalibData.accX_zero);
+ SETLONG(av + 2, x->wiiremote->nunchukCalibData.accY_zero);
+ SETLONG(av + 3, x->wiiremote->nunchukCalibData.accZ_zero);
+ SETLONG(av + 4, x->wiiremote->nunchukCalibData.accX_1g);
+ SETLONG(av + 5, x->wiiremote->nunchukCalibData.accY_1g);
+ SETLONG(av + 6, x->wiiremote->nunchukCalibData.accZ_1g);
+ outlet_anything(x->dataOut, gensym(nunchukStr), 7, 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)
+ {
+ 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);
+
+ if (x->wiiremote->isExtraOutputEnabled) // B7
+ {
+ SETSYM(av, gensym("irraw"));
+ SETLONG(av + 1, 0);
+ SETLONG(av + 2, x->wiiremote->irData[0].x);
+ SETLONG(av + 3, x->wiiremote->irData[0].y);
+ SETLONG(av + 4, x->wiiremote->irData[0].s);
+ outlet_anything(x->dataOut, gensym(remoteStr), 5, av);
+ SETLONG(av + 1, 1);
+ SETLONG(av + 2, x->wiiremote->irData[1].x);
+ SETLONG(av + 3, x->wiiremote->irData[1].y);
+ SETLONG(av + 4, x->wiiremote->irData[1].s);
+ outlet_anything(x->dataOut, gensym(remoteStr), 5, av);
+ SETLONG(av + 1, 2);
+ SETLONG(av + 2, x->wiiremote->irData[2].x);
+ SETLONG(av + 3, x->wiiremote->irData[2].y);
+ SETLONG(av + 4, x->wiiremote->irData[2].s);
+ outlet_anything(x->dataOut, gensym(remoteStr), 5, av);
+ SETLONG(av + 1, 3);
+ SETLONG(av + 2, x->wiiremote->irData[3].x);
+ SETLONG(av + 3, x->wiiremote->irData[3].y);
+ SETLONG(av + 4, x->wiiremote->irData[3].s);
+ outlet_anything(x->dataOut, gensym(remoteStr), 5, av);
+ }
+ }
+
+ // Motion Sensor
+ if (x->wiiremote->isMotionSensorEnabled)
+ {
+ 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);
+
+ if (x->wiiremote->isExtraOutputEnabled) // B7
+ {
+ SETSYM(av, gensym("motion_calibration"));
+ SETLONG(av + 1, x->wiiremote->wiiCalibData.accX_zero);
+ SETLONG(av + 2, x->wiiremote->wiiCalibData.accY_zero);
+ SETLONG(av + 3, x->wiiremote->wiiCalibData.accZ_zero);
+ SETLONG(av + 4, x->wiiremote->wiiCalibData.accX_1g);
+ SETLONG(av + 5, x->wiiremote->wiiCalibData.accY_1g);
+ SETLONG(av + 6, x->wiiremote->wiiCalibData.accZ_1g);
+ outlet_anything(x->dataOut, gensym(remoteStr), 7, av);
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------
+
+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)
+{
+ post("akawiiremote_connect");
+ t_atom status;
+ Boolean result;
+
+ if (wiiremote_isconnected(x->wiiremote))
+ {
+ SETLONG(&status, -1);
+ outlet_anything(x->statusOut, gensym("connect"), 1, &status);
+ }
+ else
+ {
+ 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
+ }
+}
+
+void akawiiremote_foundFunc(t_akawiiremote *x)
+{
+}
+
+void akawiiremote_disconnect(t_akawiiremote *x)
+{
+ post("akawiiremote_disconnect");
+
+ 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);
+
+ x->connected = !result;
+}
+
+//--------------------------------------------------------------------------------------------
+
+void akawiiremote_motionsensor(t_akawiiremote *x, long enable)
+{
+ Boolean result;
+
+ 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)
+{
+ Boolean result;
+
+ result = wiiremote_irsensor(x->wiiremote, enable);
+ //SETLONG(&status, result);
+ //outlet_anything(x->statusOut, gensym("ir"), 1, &status);
+}
+
+void akawiiremote_extraoutput(t_akawiiremote *x, long enable) // B7
+{
+ x->wiiremote->isExtraOutputEnabled = enable;
+}
+
+void akawiiremote_expansion(t_akawiiremote *x, long enable)
+{
+ Boolean result;
+
+ 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)
+{
+ Boolean result;
+
+ 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)
+{
+ Boolean result;
+
+ result = wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4);
+ //SETLONG(&status, result);
+ //outlet_anything(x->statusOut, gensym("led"), 1, &status);
+}
+
+//--------------------------------------------------------------------------------------------
+
+void akawiiremote_getbattery(t_akawiiremote *x)
+{
+ 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);
+ }
+}
+
+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_getcalibration(t_akawiiremote *x)
+{
+ 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_getaddress(t_akawiiremote *x)
+{
+ 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 connection;
+ t_atom status;
+
+ connection = wiiremote_isconnected(x->wiiremote);
+
+ if (x->connected == false && connection == true) // if the device is connected...
+ {
+ wiiremote_getstatus(x->wiiremote);
+ x->connected = true;
+ SETLONG(&status, 1);
+ outlet_anything(x->statusOut, gensym("connect"), 1, &status);
+ }
+
+ if (x->connected == true && connection == false)
+ {
+ x->connected = false;
+ SETLONG(&status, 0);
+ outlet_anything(x->statusOut, gensym("connect"), 1, &status);
+ }
+
+ clock_delay(x->clock, kInterval); // 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,"data messages"); break;
+ case 2: sprintf(s,"status messages"); break;
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------
+
+void *akawiiremote_new(t_symbol *s, short ac, t_atom *av)
+{
+#ifdef PD
+ t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class);
+ t_symbol *first_argument;
+
+ x->statusOut = outlet_new(&x->x_obj, 0);
+ x->dataOut = outlet_new(&x->x_obj, &s_list);
+
+/* this sets the device name from the object arguments */
+ first_argument = atom_getsymbolarg(0, ac, av);
+ if(first_argument != &s_)
+ atom_string(av, x->address, MAXPDSTRING-1);
+#else /* Max */
+ t_akawiiremote *x;
+
+ x = (t_akawiiremote *)newobject(akawiiremote_class);
+
+ x->statusOut = outlet_new(x, 0);
+ x->dataOut = outlet_new(x, 0);
+
+ if (ac>0 && av[0].a_type == A_SYM)
+ strcpy(x->address, av[0].a_w.w_sym->s_name);
+#endif /* PD */
+
+ 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->wiiremote->isExtraOutputEnabled = false;
+ }
+
+ x->clock = clock_new(x, (method)akawiiremote_clock);
+
+ x->connected = false;
+
+ return x;
+}
+
+void akawiiremote_free(t_akawiiremote *x)
+{
+ if (x->wiiremote != nil)
+ {
+ if (wiiremote_isconnected(x->wiiremote))
+ wiiremote_disconnect(x->wiiremote);
+ freebytes(x->wiiremote, sizeof(WiiRemoteRec));
+ x->wiiremote = nil;
+ }
+
+ clock_unset(x->clock);
+#ifdef PD
+ clock_free(x->clock);
+#else /* Max */
+ freeobject((t_object *)x->clock);
+#endif /* PD */
+}
+
diff --git a/aka.wiiremote/wiiremote-help.pd b/aka.wiiremote/wiiremote-help.pd
new file mode 100644
index 0000000..5c8f610
--- /dev/null
+++ b/aka.wiiremote/wiiremote-help.pd
@@ -0,0 +1,80 @@
+#N canvas 287 96 744 626 10;
+#X msg 128 207 connect;
+#X msg 141 228 disconnect;
+#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 127 285 metro 100;
+#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 89 283 bang;
+#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote
+with your computer (only required for the first use).;
+#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs
+will start blinking.;
+#X text 49 109 - Click on the [connect( message \, the LEDs will stop
+blinking once its connected;
+#X text 49 139 - Start the [metro] to get updates from [wiiremote]
+;
+#X obj 399 526 pddp/print;
+#X obj 354 556 pddp/print;
+#X obj 354 410 route remote;
+#X msg 503 290 getbattery;
+#X msg 503 310 getled;
+#X msg 503 330 getexpansion;
+#X obj 489 431 print RIGHT;
+#X obj 253 430 print LEFT;
+#X obj 354 476 route motion buttons ir;
+#X obj 444 497 pddp/print;
+#X msg 294 224 ir \$1;
+#X msg 218 225 motion \$1;
+#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 344 224 vibration \$1;
+#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 434 224 expansion \$1;
+#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 524 223 extraoutput \$1;
+#N canvas 254 342 450 300 address 0;
+#X obj 176 252 outlet;
+#X msg 206 126 getaddress;
+#X msg 176 72 address 00-1e-35-4c-e6-f1;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X restore 25 462 pd address;
+#X msg 503 352 getaddress;
+#X obj 631 536 dac~;
+#X obj 632 408 pddp/dsp;
+#X obj 640 500 osc~ 100;
+#X obj 303 388 wiiremote 00-1e-35-4c-e6-f1;
+#X connect 0 0 34 0;
+#X connect 1 0 34 0;
+#X connect 2 0 22 0;
+#X connect 3 0 21 0;
+#X connect 4 0 34 0;
+#X connect 5 0 4 0;
+#X connect 6 0 34 0;
+#X connect 13 0 19 0;
+#X connect 13 1 17 0;
+#X connect 14 0 34 0;
+#X connect 15 0 34 0;
+#X connect 16 0 34 0;
+#X connect 19 0 12 0;
+#X connect 19 1 11 0;
+#X connect 19 2 20 0;
+#X connect 21 0 34 0;
+#X connect 22 0 34 0;
+#X connect 23 0 24 0;
+#X connect 24 0 34 0;
+#X connect 25 0 26 0;
+#X connect 26 0 34 0;
+#X connect 27 0 28 0;
+#X connect 28 0 34 0;
+#X connect 30 0 34 0;
+#X connect 33 0 31 0;
+#X connect 33 0 31 1;
+#X connect 34 0 18 0;
+#X connect 34 1 13 0;
diff --git a/aka.wiiremote/wiiremote.c b/aka.wiiremote/wiiremote.c
new file mode 100644
index 0000000..481085e
--- /dev/null
+++ b/aka.wiiremote/wiiremote.c
@@ -0,0 +1,1087 @@
+// wiiremote.c
+// Copyright by Masayuki Akamatsu
+// Based on "DarwiinRemote" by Hiroaki Kimura
+
+#include "wiiremote.h"
+#include <unistd.h>
+
+// this type is used a lot (data array):
+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);
+
+
+//--------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------
+
+void wiiremote_init(WiiRemoteRef wiiremote)
+{
+ wiiremote->inquiry = nil;
+ wiiremote->device = nil;
+ 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->readingRegister = false;
+ wiiremote->isMotionSensorEnabled = false;
+ wiiremote->isVibrationEnabled = false;
+ wiiremote->isIRSensorEnabled = false;
+ wiiremote->wiiIRMode = kWiiIRModeExtended;
+ wiiremote->isExpansionPortEnabled = false;
+ wiiremote->isExpansionPortAttached = false;
+ wiiremote->expType = WiiExpNotAttached;
+
+ 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;
+
+}
+
+//--------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------
+
+Boolean openCChan(WiiRemoteRef wiiremote)
+{
+ short i;
+ IOReturn ret;
+
+ // open L2CAPChannel : BluetoothL2CAPPSM = 17
+ for (i=0; i<kTrial; i++)
+ {
+ ret = IOBluetoothDeviceOpenL2CAPChannelSync(wiiremote->device, &(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);
+}
+
+Boolean openIChan(WiiRemoteRef wiiremote)
+{
+ short i;
+ IOReturn ret;
+
+ // open L2CAPChannel : BluetoothL2CAPPSM = 19
+ for (i=0; i<kTrial; i++)
+ {
+ ret = IOBluetoothDeviceOpenL2CAPChannelSync(wiiremote->device, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote);
+ if ( ret == kIOReturnSuccess)
+ break;
+ usleep(kWait); // wait 10ms
+ }
+ if (i==kTrial)
+ {
+ 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; i<kTrial; i++)
+ {
+ ret = IOBluetoothL2CAPChannelWriteSync(wiiremote->cchan, 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<length ; i++)
+ cmd[i+6] = data[i];
+
+ for(;i<16 ; i++)
+ cmd[i+6]= 0;
+
+ cmd[0] = 0x16;
+ cmd[1] = (addr>>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)
+{
+ post("checkDevice");
+ 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)
+ {
+ if ( CFStringGetLength(wiiremote->address) == 0
+ || CFStringCompare(address, wiiremote->address, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ {
+ wiiremote->device = IOBluetoothObjectRetain(device);
+ if ( wiiremote_connect(wiiremote) == false )
+ wiiremote_disconnect(wiiremote);
+ }
+ }
+ }
+}
+
+void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device)
+{
+ post("myFoundFunc");
+ checkDevice((WiiRemoteRef)refCon, device);
+}
+
+void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining)
+{
+ post("myUpdatedFunc");
+
+ checkDevice((WiiRemoteRef)refCon, device);
+}
+
+void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted)
+{
+ post("myCompleteFunc");
+
+ if (aborted) return; // called by stop ;)
+
+ if (error != kIOReturnSuccess)
+ {
+ wiiremote_stopsearch((WiiRemoteRef)refCon);
+ return;
+ }
+#ifdef PD
+ // PD doesn't use the Carbon loop, so we have to manually control it
+ CFRunLoopStop( CFRunLoopGetCurrent() );
+#endif
+}
+
+//--------------------------------------------------------------------------------------------
+
+Boolean wiiremote_isconnected(WiiRemoteRef wiiremote)
+{
+ Boolean result;
+
+ result = wiiremote->device != nil && IOBluetoothDeviceIsConnected(wiiremote->device);
+ return result;
+}
+
+Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address)
+{
+ post("wiiremote_search");
+ IOReturn ret;
+
+ if (wiiremote->inquiry != nil)
+ return true;
+
+ wiiremote->inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon((void *)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)
+ {
+ IOBluetoothDeviceInquiryDelete(wiiremote->inquiry);
+ wiiremote->inquiry = nil;
+ return false;
+ }
+#ifdef PD
+ CFRunLoopRun(); // PD doesn't use the Carbon loop, so we have to manually control it
+#endif
+ return true;
+}
+
+Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote)
+{
+ post("wiiremote_stopsearch");
+ IOReturn ret;
+
+ if (wiiremote->inquiry == nil)
+ {
+ return true; // already stopped
+ }
+
+ ret = IOBluetoothDeviceInquiryStop(wiiremote->inquiry);
+
+ if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted)
+ {
+ // kIOReturnNotPermitted is if it's already stopped
+ }
+
+ IOBluetoothDeviceInquiryDelete(wiiremote->inquiry);
+ wiiremote->inquiry = nil;
+
+ return (ret==kIOReturnSuccess);
+}
+
+//--------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------
+
+unsigned char decrypt(unsigned char data)
+{
+ return (data ^ 0x17) + 0x17;
+}
+
+//--------------------------------------------------------------------------------------------
+
+/**
+* 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))
+ {
+ 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;
+}
+
+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->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)
+ {
+ if (absz > 5)
+ wiiremote->nOrientation = (wiiremote->nLowZ > 128) ? 0 : 2;
+ }
+ else
+ {
+ 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;
+
+ 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;
+ }
+}
+
+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;
+ if (wiiremote->leftPoint == -1)
+ {
+ switch (wiiremote->orientation)
+ {
+ 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;
+ }
+
+ 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;
+
+ 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;
+
+ // 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
+ {
+ ox = oy = -100;
+ wiiremote->leftPoint = -1; // not tracking
+ wiiremote->angle = -100;
+ 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)
+ {
+ // 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);
+ }
+ else
+ if (event->eventType == 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).
+ }
+}
+
+void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef)
+{
+ 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);
+
+}
+
+//--------------------------------------------------------------------------------------------
+
+Boolean wiiremote_connect(WiiRemoteRef wiiremote)
+{
+ IOReturn ret;
+ Boolean result;
+ short i;
+
+ if (wiiremote->device == nil)
+ return false;
+
+ // connect the device
+ for (i=0; i<kTrial; i++)
+ {
+ ret = IOBluetoothDeviceOpenConnection(wiiremote->device, nil, nil);
+ if ( ret == kIOReturnSuccess)
+ break;
+ usleep(kWait); // wait 10ms
+ }
+ if (i==kTrial)
+ return false;
+
+ wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, (void *)wiiremote);
+
+ // performs an SDP query
+ for (i=0; i<kTrial; i++)
+ {
+ ret = IOBluetoothDevicePerformSDPQuery(wiiremote->device, nil, nil);
+ if ( ret == kIOReturnSuccess)
+ break;
+ usleep(kWait); // wait 10ms
+ }
+ if (i==kTrial)
+ return false;
+
+ result = openCChan(wiiremote);
+ result = openIChan(wiiremote);
+
+ if (result)
+ {
+ result = wiiremote_led(wiiremote, wiiremote->isLED1Illuminated, wiiremote->isLED2Illuminated, wiiremote->isLED3Illuminated, wiiremote->isLED4Illuminated);
+ }
+
+ if (result == false)
+ {
+ wiiremote_disconnect(wiiremote);
+ return result;
+ }
+
+ wiiremote_getstatus(wiiremote);
+ requestUpdates(wiiremote);
+
+ readData(wiiremote, 0x0020, 7); // Get Accelerometer callibration data
+
+ return true;
+}
+
+
+Boolean wiiremote_disconnect(WiiRemoteRef wiiremote)
+{
+ short i = 0;
+
+ if (wiiremote->cchan)
+ {
+ if (IOBluetoothDeviceIsConnected(wiiremote->device))
+ {
+ for (i=0; i<kTrial; i++)
+ {
+ if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan) == kIOReturnSuccess)
+ break;
+ usleep(kWait); // wait 10ms
+ }
+ }
+ if (i==kTrial) return false;
+ IOBluetoothObjectRelease(wiiremote->cchan);
+ wiiremote->cchan = nil;
+ }
+
+ if (wiiremote->ichan)
+ {
+ if (IOBluetoothDeviceIsConnected(wiiremote->device))
+ {
+ for (i=0; i<kTrial; i++)
+ {
+ if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->ichan) == kIOReturnSuccess)
+ break;
+ }
+ }
+ if (i==kTrial) return false;
+ IOBluetoothObjectRelease(wiiremote->ichan);
+ wiiremote->ichan = nil;
+ }
+
+ if (wiiremote->device)
+ {
+ if (IOBluetoothDeviceIsConnected(wiiremote->device))
+ {
+ for (i=0; i<kTrial; i++)
+ {
+ if (IOBluetoothDeviceCloseConnection(wiiremote->device) == kIOReturnSuccess)
+ break;
+ }
+ }
+ if (i==kTrial) return false;
+ IOBluetoothObjectRelease(wiiremote->device);
+ wiiremote->device = nil;
+ }
+
+ if (wiiremote->disconnectNotification != nil)
+ {
+ IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification);
+ wiiremote->disconnectNotification = nil;
+ }
+
+ return true;
+}
+
+//--------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------
+
+Boolean requestUpdates(WiiRemoteRef wiiremote)
+{
+ Boolean result;
+
+ // Set the report type the Wiimote should send.
+ unsigned char cmd[] = {0x12, 0x02, 0x30}; // Just buttons.
+
+ if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01;
+
+ /*
+ There are numerous status report types that can be requested.
+ The IR reports must be matched with the data format set when initializing the IR camera:
+ 0x36, 0x37 - 10 IR bytes go with Basic mode
+ 0x33 - 12 IR bytes go with Extended mode
+ 0x3e/0x3f - 36 IR bytes go with Full mode
+
+ The Nunchuk and Classic controller use 6 bytes to report their state, so the reports that
+ give more extension bytes don't provide any more info.
+
+ Buttons | Accelerometer | IR | Extension
+ --------------------+-------------------+-----------+-------------
+ 0x30: Core Buttons | | |
+ 0x31: Core Buttons | Accelerometer | |
+ 0x32: Core Buttons | | | 8 bytes
+ 0x33: Core Buttons | Accelerometer | 12 bytes |
+ 0x34: Core Buttons | | | 19 bytes
+ 0x35: Core Buttons | Accelerometer | | 16 bytes
+ 0x36: Core Buttons | | 10 bytes | 9 bytes
+ 0x37: Core Buttons | Accelerometer | 10 bytes | 6 bytes
+ ?? 0x38: Core Buttons and Accelerometer with 16 IR bytes ??
+ 0x3d: | | | 21 bytes
+
+ 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 16/36 IR bytes
+
+ */
+
+ if (wiiremote->isIRSensorEnabled)
+ {
+ 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
+ }
+ }
+
+ if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; // Add Accelerometer
+
+ usleep(kWait); // wait 10ms
+ result = sendCommand(wiiremote, cmd, 3);
+
+ return(result);
+}
+
+//--------------------------------------------------------------------------------------------
+
+Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled)
+{
+ wiiremote->isMotionSensorEnabled = enabled;
+ return requestUpdates(wiiremote);
+}
+
+Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled)
+{
+
+ wiiremote->isVibrationEnabled = enabled;
+ return requestUpdates(wiiremote);
+}
+
+Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4)
+{
+ unsigned char cmd[] = {0x11, 0x00};
+ if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01;
+ if (enabled1) cmd[1] |= 0x10;
+ if (enabled2) cmd[1] |= 0x20;
+ if (enabled3) cmd[1] |= 0x40;
+ if (enabled4) cmd[1] |= 0x80;
+
+ wiiremote->isLED1Illuminated = enabled1;
+ wiiremote->isLED2Illuminated = enabled2;
+ wiiremote->isLED3Illuminated = enabled3;
+ wiiremote->isLED4Illuminated = enabled4;
+
+ 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};
+ return sendCommand(wiiremote, cmd, 2);
+}
+
+
diff --git a/aka.wiiremote/wiiremote.h b/aka.wiiremote/wiiremote.h
new file mode 100644
index 0000000..4a03f09
--- /dev/null
+++ b/aka.wiiremote/wiiremote.h
@@ -0,0 +1,175 @@
+// 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>
+
+// 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;
+ 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;
+
+ WiiExpansionPortType expType;
+ WiiAccCalibData wiiCalibData, nunchukCalibData;
+ WiiJoyStickCalibData nunchukJoyStickCalibData;
+ WiiIRModeType wiiIRMode;
+ IRData irData[4];
+ double batteryLevel;
+
+ Boolean readingRegister;
+ Boolean isMotionSensorEnabled;
+ Boolean isIRSensorEnabled;
+ Boolean isVibrationEnabled;
+ Boolean isExpansionPortEnabled;
+ Boolean initExpPort;
+ Boolean isLED1Illuminated;
+ Boolean isLED2Illuminated;
+ Boolean isLED3Illuminated;
+ Boolean isLED4Illuminated;
+ Boolean isExtraOutputEnabled;
+
+ 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, 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);
+