aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2009-10-03 15:35:26 +0000
committerIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2009-10-03 15:35:26 +0000
commit7855414d370528846082416bac88e8e8d4023465 (patch)
treed52918f21d77af1b95b4929df83177d52dea395e
[wiimote] by Mike Wozniewki (with fixes by Florian Krebs and IO)svn2git-root
svn path=/trunk/externals/hardware/wiimote/; revision=12512
-rw-r--r--makefile65
-rw-r--r--wiimote-help.pd325
-rw-r--r--wiimote.c624
3 files changed, 1014 insertions, 0 deletions
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..1258850
--- /dev/null
+++ b/makefile
@@ -0,0 +1,65 @@
+NAME=wiimote
+SYM=wiimote
+
+# If you want to use a customized Pd, then define a $PD_PATH variable.
+# Otherwise, the Pd must be installed on the system
+PD_PATH=../../../pd
+
+# specify the path to CWiid:
+#CWIID_PATH = $(ASCAPE_PATH)/usr/lib
+LIBCWIID_PATH = "cwiid-svn/libcwiid"
+
+######################################################
+# You shouldn't need to change anything beyond here! #
+######################################################
+
+
+ifdef PD_PATH
+PD_INCLUDE := -I$(PD_PATH)/src
+PD_EXTRA_PATH := ../../../../lib/libs
+PD_DOC_PATH := ../../../../lib/pd-help
+else
+PD_INCLUDE := -I../../../pd/src
+PD_EXTRA_PATH := /usr/local/lib/pd/extra
+PD_DOC_PATH := /usr/local/lib/pd/doc
+endif
+
+
+LIBS = $(LIBCWIID_PATH)/libcwiid.a -lbluetooth -lpthread
+#LIBS = -lcwiid -lbluetooth -lpthread
+
+current: pd_linux
+
+##### LINUX:
+
+pd_linux: $(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.pd_linux:
+ $(CC) $(LINUXCFLAGS) $(PD_INCLUDE) -o $*.o -c $*.c
+ $(LD) --export-dynamic -shared -o $*.pd_linux $*.o $(LIBS) -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o
+
+install:
+
+ifdef ASCAPE_INSTALLED
+ -cp *help*.pd $(ASCAPE_PATH)/ss_engine/pd/help/.
+ifeq ($(findstring Linux,$(ASCAPE_OS)),Linux)
+ -cp *.pd_linux $(ASCAPE_PATH)/ss_engine/pd/externs/$(ASCAPE_OS)$(ASCAPE_ARCH)/.
+endif
+ifeq ($(findstring Darwin,$(SS_OS)),Darwin)
+ -cp *.pd_darwin $(ASCAPE_PATH)/ss_engine/pd/externs/$(ASCAPE_OS)$(ASCAPE_ARCH)/.
+endif
+endif
+
+ -cp *.pd_linux $(PD_EXTRA_PATH)/.
+ -cp *help*.pd $(PD_DOC_PATH)/.
+
+clean:
+ -rm -f *.o *.pd_* so_locations
diff --git a/wiimote-help.pd b/wiimote-help.pd
new file mode 100644
index 0000000..3beb620
--- /dev/null
+++ b/wiimote-help.pd
@@ -0,0 +1,325 @@
+#N struct IR-blobs float x float y symbol s;
+#N struct NC-stick float x float y symbol s;
+#N canvas 134 135 881 633 10;
+#X msg 19 322 disconnect;
+#X obj 280 309 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X msg 60 95 discover;
+#X obj 122 396 wiimote;
+#X msg 280 339 setRumble \$1;
+#X obj 216 186 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 122 186 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X msg 216 216 reportAcceleration \$1;
+#X msg 122 216 reportIR \$1;
+#N canvas 25 33 700 644 \$0-accelerometer-stuff 0;
+#X obj 218 12 inlet;
+#X obj 366 221 unpack 0 0 0;
+#X obj 92 612 expr sqrt(pow($f1 \, 2) + pow($f2 \, 2) + pow($f3 \,
+2));
+#X obj 357 280 atan;
+#X obj 357 259 expr $f1 / $f2;
+#X obj 389 304 expr if ($f1 > 0 \, 3.14159 \, -3.14159);
+#X obj 357 331 pack 0 0 0;
+#X obj 357 353 expr if ($f3 <= 0 \, $f1 + $f2 \, $f1);
+#X obj 357 375 * -1;
+#X obj 328 61 unpack 0 0 0;
+#X obj 42 443 s \$0-wii-pitch-set;
+#X obj 357 445 s \$0-wii-roll-set;
+#X obj 407 81 s \$0-wii-accZ-set;
+#X obj 367 100 s \$0-wii-accY-set;
+#X obj 328 119 s \$0-wii-accX-set;
+#X text 75 514 The pitch and roll are only accurate if there are no
+extra accelerations due to hand movement. We can check if the total
+acceleration is close to gravity and only use pitch and roll in that
+case. The total acceleration is given by:;
+#X text 340 39 raw accerlation:;
+#X obj 31 221 unpack 0 0 0;
+#X obj 42 280 atan;
+#X obj 42 259 expr $f1 / $f2;
+#X obj 74 304 expr if ($f1 > 0 \, 3.14159 \, -3.14159);
+#X obj 42 331 pack 0 0 0;
+#X obj 42 353 expr if ($f3 <= 0 \, $f1 + $f2 \, $f1);
+#X obj 42 375 * -1;
+#X obj 225 578 unpack 0 0 0;
+#X connect 0 0 9 0;
+#X connect 0 0 17 0;
+#X connect 0 0 1 0;
+#X connect 1 0 4 0;
+#X connect 1 0 5 0;
+#X connect 1 2 4 1;
+#X connect 1 2 6 2;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 6 1;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 11 0;
+#X connect 9 0 14 0;
+#X connect 9 1 13 0;
+#X connect 9 2 12 0;
+#X connect 17 1 19 0;
+#X connect 17 1 20 0;
+#X connect 17 2 19 1;
+#X connect 17 2 21 2;
+#X connect 18 0 21 0;
+#X connect 19 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 22 0 23 0;
+#X connect 23 0 10 0;
+#X connect 24 0 2 0;
+#X connect 24 1 2 1;
+#X connect 24 2 2 2;
+#X restore 130 475 pd \$0-accelerometer-stuff;
+#N canvas 0 0 652 563 \$0-IR-stuff 0;
+#X obj 134 18 inlet;
+#X obj 122 510 pointer;
+#X msg 122 488 traverse pd-IR-data \, next;
+#X obj 134 63 route 0 1 2 3;
+#X obj 23 482 unpack 0 0 0;
+#X floatatom 483 44 5 0 0 0 IR-Blob: - -;
+#X floatatom 522 44 5 0 0 0 - - -;
+#X floatatom 562 44 5 0 0 0 - - -;
+#X obj 15 533 set IR-blobs x y;
+#X obj 231 400 pointer;
+#X obj 132 372 unpack 0 0 0;
+#X obj 124 423 set IR-blobs x y;
+#X msg 231 378 traverse pd-IR-data \, next \, next;
+#X obj 231 357 loadbang;
+#X obj 122 467 loadbang;
+#X obj 320 289 pointer;
+#X obj 221 261 unpack 0 0 0;
+#X obj 213 312 set IR-blobs x y;
+#X obj 320 246 loadbang;
+#X msg 320 267 traverse pd-IR-data \, next \, next \, next;
+#X obj 380 177 pointer;
+#X obj 281 149 unpack 0 0 0;
+#X obj 273 200 set IR-blobs x y;
+#X obj 380 134 loadbang;
+#X msg 380 155 traverse pd-IR-data \, next \, next \, next \, next
+;
+#X connect 0 0 3 0;
+#X connect 1 0 8 2;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 1 10 0;
+#X connect 3 2 16 0;
+#X connect 3 3 21 0;
+#X connect 4 0 8 0;
+#X connect 4 1 8 1;
+#X connect 9 0 11 2;
+#X connect 10 0 11 0;
+#X connect 10 1 11 1;
+#X connect 12 0 9 0;
+#X connect 13 0 12 0;
+#X connect 14 0 2 0;
+#X connect 15 0 17 2;
+#X connect 16 0 17 0;
+#X connect 16 1 17 1;
+#X connect 18 0 19 0;
+#X connect 19 0 15 0;
+#X connect 20 0 22 2;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 23 0 24 0;
+#X connect 24 0 20 0;
+#X restore 139 453 pd \$0-IR-stuff;
+#X msg 408 356 setLED \$1;
+#X obj 408 307 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 432 307 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 456 307 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 480 307 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X text 365 306 LEDs:;
+#N canvas 0 0 409 401 bytemask 0;
+#X obj 269 332 outlet;
+#X obj 269 279 float;
+#X obj 318 183 |;
+#X obj 110 239 -;
+#X obj 110 204 float;
+#X obj 110 184 trigger bang float;
+#X obj 231 204 &;
+#X obj 183 142 route 0 1;
+#X msg 36 56 \$1 1;
+#X msg 106 56 \$1 2;
+#X msg 176 56 \$1 4;
+#X msg 246 56 \$1 8;
+#X obj 36 15 inlet;
+#X obj 106 15 inlet;
+#X obj 176 15 inlet;
+#X obj 246 15 inlet;
+#X obj 36 35 change;
+#X obj 106 35 change;
+#X obj 176 35 change;
+#X obj 246 35 change;
+#X connect 1 0 2 1;
+#X connect 1 0 4 1;
+#X connect 1 0 6 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 5 1 6 0;
+#X connect 6 0 3 1;
+#X connect 7 0 5 0;
+#X connect 7 1 2 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 7 0;
+#X connect 11 0 7 0;
+#X connect 12 0 16 0;
+#X connect 13 0 17 0;
+#X connect 14 0 18 0;
+#X connect 15 0 19 0;
+#X connect 16 0 8 0;
+#X connect 17 0 9 0;
+#X connect 18 0 10 0;
+#X connect 19 0 11 0;
+#X restore 408 333 pd bytemask;
+#X obj 161 589 wiimote 00:19:1D:BE:6A:66;
+#X text 5 6 IN ORDER TO CONNECT: First put the wiimote into discover
+mode (press buttons 1 and 2 simultaneously).;
+#X text 221 68 <- Then you can connect to a specific address;
+#X text 127 96 <- Or you can try to automatically detect a wiimote.
+;
+#X obj 375 186 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X text 74 557 You can also specify the address as a creation argument:
+;
+#X text 115 138 By default \, the wiimote does not report acceleration
+data \, IR data \, or any data from an attached extension (eg \, nunchuck).
+You must specifically enable each reporting mode:;
+#X text 86 571 (make sure to enable discover mode before creation)
+;
+#X msg 375 216 reportNunchuck \$1;
+#N canvas 0 0 920 244 \$0-nunchuck-stuff 0;
+#X obj 559 61 inlet;
+#X obj 672 134 pointer;
+#X obj 672 91 loadbang;
+#X obj 559 96 unpack 0 0;
+#X obj 565 179 set NC-stick x y;
+#X obj 49 71 inlet;
+#X text 42 32 inlet #1: BUTTONS;
+#X text 294 35 inlet #2: ACCELERATION;
+#X obj 304 72 inlet;
+#X obj 304 105 unpack 0 0 0;
+#X obj 383 125 s \$0-nc-accZ-set;
+#X obj 343 144 s \$0-nc-accY-set;
+#X obj 304 163 s \$0-nc-accX-set;
+#X text 567 32 inlet #3: STICK;
+#X obj 49 117 s \$0-nc-btn-set;
+#X msg 672 112 traverse pd-NC-data \, next;
+#X connect 0 0 3 0;
+#X connect 1 0 4 2;
+#X connect 2 0 15 0;
+#X connect 3 0 4 0;
+#X connect 3 1 4 1;
+#X connect 5 0 14 0;
+#X connect 8 0 9 0;
+#X connect 9 0 12 0;
+#X connect 9 1 11 0;
+#X connect 9 2 10 0;
+#X connect 15 0 1 0;
+#X restore 148 430 pd \$0-nunchuck-stuff;
+#X obj 579 406 cnv 15 275 230 empty empty Nunchuk: 10 15 0 14 -228992
+-355 0;
+#X floatatom 756 470 7 0 0 1 _X #0-nc-accX-set #0-nc-accX;
+#X floatatom 756 484 7 0 0 1 _Y #0-nc-accY-set #0-nc-accY;
+#X floatatom 756 498 7 0 0 1 _Z #0-nc-accZ-set #0-nc-accZ;
+#X obj 626 470 hsl 128 14 -1 1 0 0 \$0-nc-accX \$0-nc-accX-set empty
+-2 -8 0 10 -261681 -1 -1 0 1;
+#X obj 626 484 hsl 128 14 -1 1 0 0 \$0-nc-accY \$0-nc-accY-set empty
+-2 -8 0 10 -261681 -1 -1 0 1;
+#X obj 626 498 hsl 128 14 -1 1 0 0 \$0-nc-accZ \$0-nc-accZ-set empty
+-2 -8 0 10 -261681 -1 -1 0 1;
+#X obj 792 429 nbx 3 16 -1e+37 1e+37 0 0 empty \$0-nc-btn-set empty
+-80 8 0 10 -261681 -1 -1 0 256;
+#X text 622 454 Acceleration:;
+#N canvas 154 209 610 221 NC-stick 0;
+#X obj 39 34 struct NC-stick float x float y;
+#X obj 44 71 filledpolygon 900 20 0 5 -5 0 -20 -5 -5 -20 0 -5 5 0 20
+5 5 20 0;
+#X restore 681 614 pd NC-stick;
+#X text 783 411 Buttons:;
+#X text 698 518 Stick:;
+#X obj 579 5 cnv 15 275 400 empty empty Wiimote: 10 15 0 14 -261689
+-143491 0;
+#X floatatom 742 80 7 0 0 1 _X #0-wii-accX-set #0-wii-accX;
+#X floatatom 742 94 7 0 0 1 _Y #0-wii-accY-set #0-wii-accY;
+#X floatatom 742 108 7 0 0 1 _Z #0-wii-accZ-set #0-wii-accZ;
+#X obj 612 80 hsl 128 14 -1 1 0 0 \$0-wii-accX \$0-wii-accX-set empty
+-2 -8 0 10 -225271 -1 -1 0 1;
+#X obj 612 94 hsl 128 14 -1 1 0 0 \$0-wii-accY \$0-wii-accY-set empty
+-2 -8 0 10 -225271 -1 -1 0 1;
+#X obj 612 108 hsl 128 14 -1 1 0 0 \$0-wii-accZ \$0-wii-accZ-set empty
+-2 -8 0 10 -225271 -1 -1 0 1;
+#N canvas 525 243 481 416 IR-data 0;
+#X scalar IR-blobs 909 63 blob1 \;;
+#X scalar IR-blobs 250.25 49 blob2 \;;
+#X scalar IR-blobs 145.5 182.25 blob3 \;;
+#X scalar IR-blobs 491.008 468.615 blob4 \;;
+#X coords 0 0 1024 768 256 196 1;
+#X restore 590 183 pd IR-data;
+#N canvas 631 449 342 204 IR-blobs 0;
+#X obj 39 34 struct IR-blobs float x float y symbol s;
+#X obj 39 71 filledcurve 9 30 0 0 -30 -30 0 0 30 30 0;
+#X obj 48 112 drawsymbol s -60 -75 0 1 blob;
+#X restore 767 379 pd IR-blobs;
+#X text 648 166 IR Blobs (1024x768):;
+#X floatatom 742 128 7 0 0 1 _PITCH #0-wii-pitch-set #0-wii-pitch;
+#X obj 612 128 hsl 128 14 -3.14156 3.14159 0 0 \$0-wii-pitch \$0-wii-pitch-set
+empty -2 -8 0 10 -225280 -1 -1 0 1;
+#X floatatom 742 142 7 0 0 1 _ROLL #0-wii-roll-set #0-wii-roll;
+#X obj 612 142 hsl 128 14 -3.14156 3.14159 0 0 \$0-wii-roll \$0-wii-roll-set
+empty -2 -8 0 10 -225280 -1 -1 0 1;
+#X text 608 64 Acceleration (-1 to 1):;
+#X obj 779 23 nbx 2 16 -1e+37 1e+37 0 0 empty \$0-wii-btn01-set empty
+-100 10 0 12 -225280 -1 -1 0 256;
+#X obj 814 23 nbx 2 16 -1e+37 1e+37 0 0 empty \$0-wii-btn02-set empty
+0 10 0 12 -225280 -1 -1 0 256;
+#N canvas 0 0 330 216 \$0-button-stuff 0;
+#X obj 41 33 inlet;
+#X obj 41 86 unpack 0 0;
+#X obj 41 140 s \$0-wii-btn01-set;
+#X obj 106 120 s \$0-wii-btn02-set;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 1 1 3 0;
+#X restore 122 497 pd \$0-button-stuff;
+#X text 783 5 Buttons:;
+#N canvas 185 133 481 416 NC-data 0;
+#X scalar NC-stick 130 133 \;;
+#X coords 0 0 256 256 80 80 1;
+#X restore 681 534 pd NC-data;
+#X obj 161 615 print;
+#X msg 36 69 connect 00:1E:35:1D:0E:15;
+#X connect 0 0 3 0;
+#X connect 1 0 4 0;
+#X connect 2 0 3 0;
+#X connect 3 0 57 0;
+#X connect 3 1 9 0;
+#X connect 3 2 10 0;
+#X connect 3 3 27 0;
+#X connect 3 4 27 1;
+#X connect 3 5 27 2;
+#X connect 4 0 3 0;
+#X connect 5 0 7 0;
+#X connect 6 0 8 0;
+#X connect 7 0 3 0;
+#X connect 8 0 3 0;
+#X connect 11 0 3 0;
+#X connect 12 0 17 0;
+#X connect 13 0 17 1;
+#X connect 14 0 17 2;
+#X connect 15 0 17 3;
+#X connect 17 0 11 0;
+#X connect 18 0 60 0;
+#X connect 22 0 26 0;
+#X connect 26 0 3 0;
+#X connect 61 0 3 0;
diff --git a/wiimote.c b/wiimote.c
new file mode 100644
index 0000000..94a1930
--- /dev/null
+++ b/wiimote.c
@@ -0,0 +1,624 @@
+// ===================================================================
+// Wiimote external for Puredata
+// Written by Mike Wozniewki (Feb 2007), www.mikewoz.com
+//
+// Requires the CWiid library (version 0.6.00) by L. Donnie Smith
+//
+// ===================================================================
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+// ===================================================================
+
+// ChangeLog:
+// 2008-04-14 Florian Krebs
+// * adapt wiimote external for the actual version of cwiid (0.6.00)
+// 2009-09-14 IOhannes m zmölnig
+// * made it compile without private cwiid-headers
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <bluetooth/bluetooth.h>
+#include <m_pd.h>
+#include <math.h>
+#include <cwiid.h>
+
+#define PI 3.14159265358979323
+
+struct acc {
+ unsigned char x;
+ unsigned char y;
+ unsigned char z;
+};
+
+/* Wiimote Callback */
+cwiid_mesg_callback_t cwiid_callback;
+
+// class and struct declarations for wiimote pd external:
+static t_class *cwiid_class;
+typedef struct _wiimote
+{
+ t_object x_obj; // standard pd object (must be first in struct)
+
+ cwiid_wiimote_t *wiimote; // individual wiimote handle per pd object, represented in libcwiid
+
+ t_float connected;
+ int wiimoteID;
+
+ t_float toggle_acc, toggle_ir, toggle_nc;
+
+ struct acc acc_zero, acc_one; // acceleration
+ struct acc nc_acc_zero, nc_acc_one; // nunchuck acceleration
+
+ // We store atom list for each data type so we don't waste time
+ // allocating memory at every callback:
+ t_atom btn_atoms[2];
+ t_atom acc_atoms[3];
+ t_atom ir_atoms[4];
+ t_atom nc_btn_atoms[2];
+ t_atom nc_acc_atoms[3];
+ t_atom nc_stick_atoms[2];
+
+ // outlets:
+ t_outlet *outlet_btn;
+ t_outlet *outlet_acc;
+ t_outlet *outlet_ir;
+ t_outlet *outlet_nc_btn;
+ t_outlet *outlet_nc_acc;
+ t_outlet *outlet_nc_stick;
+
+} t_wiimote;
+
+
+
+
+// For now, we make one global t_wiimote pointer that we can refer to
+// in the cwiid_callback. This means we can support maximum of ONE
+// wiimote. ARGH. We'll have to figure out how to have access to the
+// pd object from the callback (without modifying the CWiid code):
+#define MAX_WIIMOTES 14
+
+typedef struct _wiimoteList {
+ t_wiimote*x;
+ int id;
+ struct _wiimoteList*next;
+} t_wiimoteList;
+
+t_wiimoteList*g_wiimoteList=NULL;
+
+int addWiimoteObject(t_wiimote*x, int id) {
+ t_wiimoteList*wl=g_wiimoteList;
+ t_wiimoteList*newentry=NULL;
+ if(NULL!=wl) {
+ while(wl->next) {
+
+ if(wl->x == x) {
+ pd_error(x, "[wiimote]: already bound to Wii%02d", wl->id);
+ return 0;
+ }
+ if(wl->id == id) {
+ pd_error(x, "[wiimote]: another object is already bound to Wii%02d", wl->id);
+ return 0;
+ }
+ wl=wl->next;
+ }
+ }
+
+ newentry=(t_wiimoteList*)getbytes(sizeof(t_wiimoteList));
+ newentry->next=NULL;
+ newentry->x=x;
+ newentry->id=id;
+
+ if(wl)
+ wl->next=newentry;
+ else
+ g_wiimoteList=newentry;
+
+ return 1;
+}
+
+t_wiimote*getWiimoteObject(const int id) {
+ t_wiimoteList*wl=g_wiimoteList;
+ if(NULL==wl)
+ return NULL;
+
+ while(wl) {
+ if(id == wl->id) {
+ return wl->x;
+ }
+ wl=wl->next;
+ }
+ return NULL;
+}
+
+void removeWiimoteObject(const t_wiimote*x) {
+ t_wiimoteList*wl=g_wiimoteList;
+ t_wiimoteList*last=NULL;
+ if(NULL==wl)
+ return;
+
+ while(wl) {
+ if(x == wl->x) {
+ if(last) {
+ last->next=wl->next;
+ } else {
+ g_wiimoteList=wl->next;
+ }
+ wl->x=NULL;
+ wl->id=0;
+ wl->next=NULL;
+ freebytes(wl, sizeof(t_wiimoteList));
+
+ return;
+ }
+ last=wl;
+ wl=wl->next;
+ }
+}
+
+
+
+// ==============================================================
+void cwiid_debug(t_wiimote *x)
+{
+ post("\n======================");
+ if (x->connected) post("Wiimote (id: %d) is connected.", x->wiimoteID);
+ else post("Wiimote (id: %d) is NOT connected.", x->wiimoteID);
+ post("acceleration: %s", (x->toggle_acc)?"ON":"OFF");
+ post("IR: %s", (x->toggle_ir)?"ON":"OFF");
+ post("nunchuck: %s", (x->toggle_nc)?"ON":"OFF");
+ post("");
+ post("Accelerometer calibration: zero=(%d,%d,%d) one=(%d,%d,%d)",x->acc_zero.x,x->acc_zero.y,x->acc_zero.z,x->acc_one.x,x->acc_one.y,x->acc_one.z);
+ post("Nunchuck calibration: zero=(%d,%d,%d) one=(%d,%d,%d)",x->nc_acc_zero.x,x->nc_acc_zero.y,x->nc_acc_zero.z,x->nc_acc_one.x,x->nc_acc_one.y,x->nc_acc_one.z);
+
+
+}
+
+// ==============================================================
+
+// Button handler:
+void cwiid_btn(t_wiimote *x, struct cwiid_btn_mesg *mesg)
+{
+ SETFLOAT(x->btn_atoms+0, (mesg->buttons & 0xFF00)>>8);
+ SETFLOAT(x->btn_atoms+1, mesg->buttons & 0x00FF);
+ outlet_anything(x->outlet_btn, &s_list, 2, x->btn_atoms);
+/*
+ if (mesg->buttons & CWIID_BTN_UP) {}
+ if (mesg->buttons & CWIID_BTN_DOWN) {}
+ if (mesg->buttons & CWIID_BTN_LEFT) {}
+ if (mesg->buttons & CWIID_BTN_RIGHT) {}
+ if (mesg->buttons & CWIID_BTN_A) {}
+ if (mesg->buttons & CWIID_BTN_B) {}
+ if (mesg->buttons & CWIID_BTN_MINUS) {}
+ if (mesg->buttons & CWIID_BTN_PLUS) {}
+ if (mesg->buttons & CWIID_BTN_HOME) {}
+ if (mesg->buttons & CWIID_BTN_1) {}
+ if (mesg->buttons & CWIID_BTN_2) {}
+*/
+
+}
+
+
+void cwiid_acc(t_wiimote *x, struct cwiid_acc_mesg *mesg)
+{
+ if (x->toggle_acc)
+ {
+ double a_x, a_y, a_z;
+
+ a_x = ((double)mesg->acc[CWIID_X] - x->acc_zero.x) / (x->acc_one.x - x->acc_zero.x);
+ a_y = ((double)mesg->acc[CWIID_Y] - x->acc_zero.y) / (x->acc_one.y - x->acc_zero.y);
+ a_z = ((double)mesg->acc[CWIID_Z] - x->acc_zero.z) / (x->acc_one.z - x->acc_zero.z);
+
+ /*
+ double a, roll, pitch;
+ a = sqrt(pow(a_x,2)+pow(a_y,2)+pow(a_z,2));
+ roll = atan(a_x/a_z);
+ if (a_z <= 0.0) roll += PI * ((a_x > 0.0) ? 1 : -1);
+ roll *= -1;
+ pitch = atan(a_y/a_z*cos(roll));
+ */
+
+ SETFLOAT(x->acc_atoms+0, a_x);
+ SETFLOAT(x->acc_atoms+1, a_y);
+ SETFLOAT(x->acc_atoms+2, a_z);
+ outlet_anything(x->outlet_acc, &s_list, 3, x->acc_atoms);
+ }
+
+}
+
+void cwiid_ir(t_wiimote *x, struct cwiid_ir_mesg *mesg)
+{
+ unsigned int i;
+
+ if (x->toggle_ir)
+ {
+ //post("IR (valid,x,y,size) #%d: %d %d %d %d", i, data->ir_data.ir_src[i].valid, data->ir_data.ir_src[i].x, data->ir_data.ir_src[i].y, data->ir_data.ir_src[i].size);
+ for (i=0; i<CWIID_IR_SRC_COUNT; i++)
+ {
+ if (mesg->src[i].valid)
+ {
+ SETFLOAT(x->ir_atoms+0, i);
+ SETFLOAT(x->ir_atoms+1, mesg->src[i].pos[CWIID_X]);
+ SETFLOAT(x->ir_atoms+2, mesg->src[i].pos[CWIID_Y]);
+ SETFLOAT(x->ir_atoms+3, mesg->src[i].size);
+ outlet_anything(x->outlet_ir, &s_list, 4, x->ir_atoms);
+ }
+ }
+ }
+}
+
+
+void cwiid_nunchuk(t_wiimote *x, struct cwiid_nunchuk_mesg *mesg)
+{
+ double a_x, a_y, a_z;
+
+ a_x = ((double)mesg->acc[CWIID_X] - x->nc_acc_zero.x) / (x->nc_acc_one.x - x->nc_acc_zero.x);
+ a_y = ((double)mesg->acc[CWIID_Y] - x->nc_acc_zero.y) / (x->nc_acc_one.y - x->nc_acc_zero.y);
+ a_z = ((double)mesg->acc[CWIID_Z] - x->nc_acc_zero.z) / (x->nc_acc_one.z - x->nc_acc_zero.z);
+
+ /*
+ double a, roll, pitch;
+ a = sqrt(pow(a_x,2)+pow(a_y,2)+pow(a_z,2));
+ roll = atan(a_x/a_z);
+ if (a_z <= 0.0) roll += PI * ((a_x > 0.0) ? 1 : -1);
+ roll *= -1;
+ pitch = atan(a_y/a_z*cos(roll));
+ */
+
+ if (mesg->buttons & CWIID_NUNCHUK_BTN_C) {}
+ if (mesg->buttons & CWIID_NUNCHUK_BTN_Z) {}
+ outlet_float(x->outlet_nc_btn, mesg->buttons);
+
+ SETFLOAT(x->nc_acc_atoms+0, a_x);
+ SETFLOAT(x->nc_acc_atoms+1, a_y);
+ SETFLOAT(x->nc_acc_atoms+2, a_z);
+ outlet_anything(x->outlet_nc_acc, &s_list, 3, x->nc_acc_atoms);
+
+ SETFLOAT(x->nc_stick_atoms+0, mesg->stick[CWIID_X]);
+ SETFLOAT(x->nc_stick_atoms+1, mesg->stick[CWIID_Y]);
+ outlet_anything(x->outlet_nc_stick, &s_list, 2, x->nc_stick_atoms);
+
+}
+
+// The CWiid library invokes a callback function whenever events are
+// generated by the wiimote. This function is specified when connecting
+// to the wiimote (in the cwiid_open function).
+
+// Unfortunately, the mesg struct passed as an argument to the
+// callback does not have a pointer to the wiimote instance, and it
+// is thus impossible to know which wiimote has invoked the callback.
+// For this case we provide a hard-coded set of wrapper callbacks to
+// indicate which Pd wiimote instance to control.
+
+// So far I have only checked with one wiimote
+
+/*void cwiid_callback(cwiid_wiimote_t *wiimt, int mesg_count, union cwiid_mesg *mesg[], struct timespec *timestamp)
+*/
+void cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count,
+ union cwiid_mesg mesg_array[], struct timespec *timestamp)
+{
+ unsigned char buf[7];
+ int i;
+ t_wiimote *x=NULL;
+
+ if(g_wiimoteList==NULL||wiimote==NULL) {
+ post("no wii's known");
+ return;
+ }
+ x=getWiimoteObject(cwiid_get_id(wiimote));
+ if(NULL==x) {
+ post("no wiimote loaded: %d%",cwiid_get_id(wiimote));
+ return;
+ }
+
+ for (i=0; i < mesg_count; i++)
+ {
+ switch (mesg_array[i].type) {
+ case CWIID_MESG_STATUS:
+ post("Battery: %d%", (int) (100.0 * mesg_array[i].status_mesg.battery / CWIID_BATTERY_MAX));
+ switch (mesg_array[i].status_mesg.ext_type) {
+ case CWIID_EXT_NONE:
+ post("No nunchuck attached");
+ break;
+ case CWIID_EXT_NUNCHUK:
+ post("Nunchuck extension attached");
+
+ if (cwiid_read(x->wiimote, CWIID_RW_REG | CWIID_RW_DECODE, 0xA40020, 7, buf)) {
+ post("Unable to retrieve Nunchuk calibration");
+ }
+ else {
+ x->nc_acc_zero.x = buf[0];
+ x->nc_acc_zero.y = buf[1];
+ x->nc_acc_zero.z = buf[2];
+ x->nc_acc_one.x = buf[4];
+ x->nc_acc_one.y = buf[5];
+ x->nc_acc_one.z = buf[6];
+ }
+ break;
+ case CWIID_EXT_CLASSIC:
+ post("Classic controller attached. There is no support for this yet.");
+ break;
+ case CWIID_EXT_UNKNOWN:
+ post("Unknown extension attached");
+ break;
+ }
+ break;
+ case CWIID_MESG_BTN:
+ cwiid_btn(x, &mesg_array[i].btn_mesg);
+ break;
+ case CWIID_MESG_ACC:
+ cwiid_acc(x, &mesg_array[i].acc_mesg);
+ break;
+ case CWIID_MESG_IR:
+ cwiid_ir(x, &mesg_array[i].ir_mesg);
+ break;
+ case CWIID_MESG_NUNCHUK:
+ cwiid_nunchuk(x, &mesg_array[i].nunchuk_mesg);
+ break;
+ case CWIID_MESG_CLASSIC:
+ // todo
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+// ==============================================================
+
+
+
+void cwiid_setReportMode(t_wiimote *x, t_floatarg r)
+{
+ unsigned char rpt_mode;
+
+ if (r >= 0) rpt_mode = (unsigned char) r;
+ else {
+ rpt_mode = CWIID_RPT_STATUS | CWIID_RPT_BTN;
+ if (x->toggle_ir) rpt_mode |= CWIID_RPT_IR;
+ if (x->toggle_acc) rpt_mode |= CWIID_RPT_ACC;
+ if (x->toggle_nc) rpt_mode |= CWIID_RPT_EXT;
+ }
+ if (x->connected)
+ {
+ verbose(1, "changing report mode for Wii%02d to %d", x->wiimoteID, rpt_mode);
+ if (cwiid_command(x->wiimote, CWIID_CMD_RPT_MODE, rpt_mode)) {
+ post("wiimote error: problem setting report mode.");
+ }
+ }
+}
+
+void cwiid_reportAcceleration(t_wiimote *x, t_floatarg f)
+{
+ x->toggle_acc = f;
+ cwiid_setReportMode(x, -1);
+}
+
+void cwiid_reportIR(t_wiimote *x, t_floatarg f)
+{
+ x->toggle_ir = f;
+ cwiid_setReportMode(x, -1);
+}
+
+void cwiid_reportNunchuck(t_wiimote *x, t_floatarg f)
+{
+ x->toggle_nc = f;
+ cwiid_setReportMode(x, -1);
+}
+void cwiid_setRumble(t_wiimote *x, t_floatarg f)
+{
+ if (x->connected)
+ {
+ if (cwiid_command(x->wiimote, CWIID_CMD_RUMBLE, f)) post("wiiremote error: problem setting rumble.");
+ }
+}
+
+void cwiid_setLED(t_wiimote *x, t_floatarg f)
+{
+ // some possible values:
+ // CWIID_LED0_ON 0x01
+ // CWIID_LED1_ON 0x02
+ // CWIID_LED2_ON 0x04
+ // CWIID_LED3_ON 0x08
+ if (x->connected)
+ {
+ if (cwiid_command(x->wiimote, CWIID_CMD_LED, f)) post("wiiremote error: problem setting LED.");
+ }
+}
+
+
+
+// ==============================================================
+
+
+// The following function attempts to connect to a wiimote at a
+// specific address, provided as an argument. eg, 00:19:1D:70:CE:72
+// This address can be discovered by running the following command
+// in a console:
+// hcitool scan | grep Nintendo
+
+void cwiid_doConnect(t_wiimote *x, t_symbol *addr, t_symbol *dongaddr)
+{
+ unsigned char buf[7];
+ int i;
+ bdaddr_t bdaddr;
+
+ bdaddr_t dong_bdaddr;
+ bdaddr_t* dong_bdaddr_ptr=&dong_bdaddr;
+
+ // determine address:
+ if (NULL==addr || addr==gensym("")) {
+ post("Searching automatically...");
+ bdaddr = *BDADDR_ANY;
+ }
+ else {
+ str2ba(addr->s_name, &bdaddr);
+ post("Connecting to given address...");
+ post("Press buttons 1 and 2 simultaneously.");
+ }
+
+ // determine dongleaddress:
+ if (NULL==dongaddr || dongaddr==gensym("")) {
+ post("Binding automatically...");
+ dong_bdaddr_ptr = NULL;
+ }
+ else {
+ str2ba(dongaddr->s_name, &dong_bdaddr);
+ }
+ // connect:
+
+
+ x->wiimote = cwiid_open(&bdaddr, dong_bdaddr_ptr, CWIID_FLAG_MESG_IFC);
+
+ if(NULL==x->wiimote) {
+ post("wiimote error: unable to connect");
+ return;
+ }
+
+ if(!addWiimoteObject(x, cwiid_get_id(x->wiimote))) {
+ cwiid_close(x->wiimote);
+ x->wiimote==NULL;
+ return;
+ }
+
+ x->wiimoteID= cwiid_get_id(x->wiimote);
+
+ post("wiimote %i is successfully connected", x->wiimoteID);
+ if (cwiid_read(x->wiimote, CWIID_RW_EEPROM, 0x16, 7, buf)) {
+ post("Unable to retrieve accelerometer calibration");
+ } else {
+ x->acc_zero.x = buf[0];
+ x->acc_zero.y = buf[1];
+ x->acc_zero.z = buf[2];
+ x->acc_one.x = buf[4];
+ x->acc_one.y = buf[5];
+ x->acc_one.z = buf[6];
+ //post("Retrieved wiimote calibration: zero=(%.1f,%.1f,%.1f) one=(%.1f,%.1f,%.1f)",buf[0],buf[2],buf[3],buf[4],buf[5],buf[6]);
+ }
+
+ x->connected = 1;
+ cwiid_setReportMode(x,-1);
+
+ if (cwiid_set_mesg_callback(x->wiimote, &cwiid_callback)) {
+ pd_error(x, "Unable to set message callback");
+ }
+}
+
+// The following function attempts to discover a wiimote. It requires
+// that the user puts the wiimote into 'discoverable' mode before being
+// called. This is done by pressing the red button under the battery
+// cover, or by pressing buttons 1 and 2 simultaneously.
+// TODO: Without pressing the buttons, I get a segmentation error. So far, I don't know why.
+
+void cwiid_discover(t_wiimote *x)
+{
+ post("Put the wiimote into discover mode by pressing buttons 1 and 2 simultaneously.");
+
+ cwiid_doConnect(x, NULL, gensym("NULL"));
+ if (!(x->connected))
+ {
+ post("Error: could not find any wiimotes. Please ensure that bluetooth is enabled, and that the 'hcitool scan' command lists your Nintendo device.");
+ }
+}
+
+void cwiid_doDisconnect(t_wiimote *x)
+{
+
+ if (x->connected)
+ {
+ if (cwiid_close(x->wiimote)) {
+ post("wiimote error: problems when disconnecting.");
+ }
+ else {
+ post("disconnect successfull, resetting values");
+ removeWiimoteObject(x);
+ x->connected = 0;
+ }
+ }
+ else post("device is not connected");
+
+}
+
+
+// ==============================================================
+// ==============================================================
+
+static void *cwiid_new(t_symbol* s, int argc, t_atom *argv)
+{
+ bdaddr_t bdaddr; // wiimote bdaddr
+ t_wiimote *x = (t_wiimote *)pd_new(cwiid_class);
+
+ // create outlets:
+ x->outlet_btn = outlet_new(&x->x_obj, &s_list);
+ x->outlet_acc = outlet_new(&x->x_obj, &s_list);
+ x->outlet_ir = outlet_new(&x->x_obj, &s_list);
+ x->outlet_nc_btn = outlet_new(&x->x_obj, &s_float);
+ x->outlet_nc_acc = outlet_new(&x->x_obj, &s_list);
+ x->outlet_nc_stick = outlet_new(&x->x_obj, &s_list);
+
+ // initialize toggles:
+ x->toggle_acc = 0;
+ x->toggle_ir = 0;
+ x->toggle_nc = 0;
+
+ x->connected = 0;
+ x->wiimoteID = -1;
+
+ // connect if user provided an address as an argument:
+
+ if (argc==2)
+ {
+ post("conecting to provided address...");
+ if (argv->a_type == A_SYMBOL)
+ {
+ cwiid_doConnect(x, NULL, atom_getsymbol(argv));
+ } else {
+ error("[wiimote] expects either no argument, or a bluetooth address as an argument. eg, 00:19:1D:70:CE:72");
+ return NULL;
+ }
+ }
+
+
+
+
+
+
+ return (x);
+}
+
+
+static void cwiid_free(t_wiimote* x)
+{
+ cwiid_doDisconnect(x);
+}
+
+void wiimote_setup(void)
+{
+ int i;
+
+ cwiid_class = class_new(gensym("wiimote"), (t_newmethod)cwiid_new, (t_method)cwiid_free, sizeof(t_wiimote), CLASS_DEFAULT, A_GIMME, 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_debug, gensym("debug"), 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_doConnect, gensym("connect"), A_SYMBOL, A_SYMBOL, 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_doDisconnect, gensym("disconnect"), 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_discover, gensym("discover"), 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_setReportMode, gensym("setReportMode"), A_DEFFLOAT, 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_reportAcceleration, gensym("reportAcceleration"), A_DEFFLOAT, 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_reportNunchuck, gensym("reportNunchuck"), A_DEFFLOAT, 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_reportIR, gensym("reportIR"), A_DEFFLOAT, 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_setRumble, gensym("setRumble"), A_DEFFLOAT, 0);
+ class_addmethod(cwiid_class, (t_method) cwiid_setLED, gensym("setLED"), A_DEFFLOAT, 0);
+}
+
+