From 7855414d370528846082416bac88e8e8d4023465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Sat, 3 Oct 2009 15:35:26 +0000 Subject: [wiimote] by Mike Wozniewki (with fixes by Florian Krebs and IO) svn path=/trunk/externals/hardware/wiimote/; revision=12512 --- makefile | 65 ++++++ wiimote-help.pd | 325 +++++++++++++++++++++++++++++ wiimote.c | 624 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1014 insertions(+) create mode 100644 makefile create mode 100644 wiimote-help.pd create mode 100644 wiimote.c 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 +#include +#include +#include +#include +#include +#include + +#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; isrc[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); +} + + -- cgit v1.2.1