The problem is however that this is not the case. Whenever issuing
rumble/led commands and/or toggling various features (enable ir, acc,
nunchuk, etc.), cwiid call causes a dropout in audio thread. It's
obvious that the initial threaded implementation done by one of my
students should've been brought to closer scrutiny by myself (rather
than assuming it actually works). Now, that I've been messing with it
myself, I am learning a lot about pthreads and have arrived at an
implementation that might seem (at least to my own limited understanding
of pthreads) more feasible, except now I am getting random crashes and
instabilities.
The basic premise is to wrap select functionalities in separate threads
(e.g. rumble on/off) as follows:
the main struct wiimote has a variable that is set only through the main
Pd thread (via incoming messages), so that whenever a rumble on message
is requested, it sets this variable to 1 and when the rumble off is
requested, it sets this variable to 0.
Another thread is spawned at creation time with a while loop whose
variable is changed in free call (destructor) and whose thread is then
exited and joined with the main thread in the free call. This thread
also has usleep instruction to ensure that it does not hog CPU. Inside
the while loop (apart from the usleep) it monitors the aforesaid
variable in the main loop to see whether it has been changed (by
comparing it to an internal variable) and if so acts upon it. Once it
has acted upon it it adjusts its internal variable to match that of the
external rumble variable. this way at least theoretically one would not
have to deal with mutex stuff (or at least as far as I could gather),
yet the thing crashes left and right. Attached is the ugly hack of a
code I have so far.
Below is also code relevant to example cited above:
//this is the separate thread that is spawned at creation
//x->rumble is variable from the main wiimote struct that is not changed
//here but rather through external messages that call the function below
//in the free() function x->rumble is set to -1 and at that point
//pthread is joined before deleting the object
void cwiid_pthread_setRumble(void *ptr)
{
threadedFunctionParams *rPars = (threadedFunctionParams*)ptr;
t_wiimote *x = rPars->wiimote;
t_floatarg f = rPars->f;
while(x->rumble > -1) {
if (f != x->rumble) {
f = x->rumble;
if (cwiid_command(x->wiimote, CWIID_CMD_RUMBLE, f)) {
//post("wiiremote error: problem setting
rumble.");
}
} else {
usleep(10000);
}
}
pthread_exit(0);
}
//this function is called when an external message arrives requesting
change in rumble status
void cwiid_setRumble(t_wiimote *x, t_floatarg f)
{
if (x->connected) {
x->rumble = f;
}
}
Any help in this is most appreciated.
Best wishes,
Ico
On Sun, 2009-10-18 at 17:04 -0400, Hans-Christoph Steiner wrote:
> I think a thread is likely just going to add complication here. The
> HID stuff is all without threads and works well. If cwiid is already
> threaded, then chances are you should be able to get data from its
> threads using non-blocking calls. If it already buffers the data,
> then you don't need your own thread, just get the data from cwiid's
> buffer in a non-blocking way.
>
> This is how the Linux input API works, IIRC.
>
> .hc
>
> On Oct 17, 2009, at 10:33 PM, Ivica Ico Bukvic wrote:
>
> > Hi all,
> >
> > I am currently working on a threaded implementation of a wiimote
> > external. The reason I was hoping threaded design would help is to
> > avoid
> > dropped samples when issuing commands to wiimote (e.g. rumble/led
> > status
> > change). So far, it seems that reading from wiimote, no matter how
> > fast,
> > has no impact on the audio thread. However, writing even when such
> > action is generated through a separate thread seems to cause drop-outs
> > in the audio thread. The external (which was not originally built by
> > me)
> > uses cwiid to communicate with wiimotes and my understanding is that
> > cwiid is heavily threaded in and of itself. An example of a threaded
> > code is below:
> >
> > void *cwiid_pthread2_setRumble(void *ptr)
> > {
> >
> > threadedFunctionParams *rPars = (threadedFunctionParams*)ptr;
> > t_wiimote *x = rPars->wiimote;
> > t_floatarg f = rPars->f;
> >
> > if (x->connected)
> > {
> > if (cwiid_command(x->wiimote, CWIID_CMD_RUMBLE, f))
> > post("wiiremote
> > error: problem setting rumble.");
> > }
> > }
> >
> > void cwiid_pthread_setRumble(t_wiimote *x, t_floatarg f)
> > {
> > threadedFunctionParams rPars;
> > rPars.wiimote = x;
> > rPars.f = f;
> >
> > pthread_t thread;
> > int iret1;
> >
> > iret1 = pthread_create( &thread, NULL, cwiid_pthread2_setRumble,
> > (void*) &rPars);
> > pthread_join(thread, NULL);
> > }
> >
> > So, cwiid_pthread_setRumble is called from Pd and then it in turn
> > creates a thread that sends info to cwiid library against which the
> > external is linked. I am confused as to why the new thread once it has
> > been created still affects the Pd's audio thread. Any ideas?
> >
> > Best wishes,
> >
> > Ico
> >
> >
> >
> >
> > _______________________________________________
> > [email protected] mailing list
> > UNSUBSCRIBE and account-management ->
> > http://lists.puredata.info/listinfo/pd-list
>
>
>
> ----------------------------------------------------------------------------
>
> "[W]e have invented the technology to eliminate scarcity, but we are
> deliberately throwing it away to benefit those who profit from
> scarcity." -John Gilmore
>
>
/* Copyright (C) 2007 L. Donnie Smith <[email protected]>
*
* 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:
* 2007-05-16 L. Donnie Smith <[email protected]>
* * remove error_pipe
* * add struct mesg_array to process_error
*
* 2007-05-14 L. Donnie Smith <[email protected]>
* * added timestamp to mesg_array
*
* 2007-04-24 L. Donnie Smith <[email protected]>
* * rewrite for API overhaul
*
* 2007-04-09 L. Donnie Smith <[email protected]>
* * renamed wiimote to libcwiid, renamed structures accordingly
*
* 2007-04-04 L. Donnie Smith <[email protected]>
* * moved RW error state to separate member
*
* 2007-04-01 L. Donnie Smith <[email protected]>
* * removed CWIID_CMP_LEN macro and cwiid_findfirst prototype
*
* 2007-03-05 L. Donnie Smith <[email protected]>
* * added wiimote parameter to cwiid_err prototype
*
* 2007-03-01 L. Donnie Smith <[email protected]>
* * Initial ChangeLog
* * type audit (stdint, const, char booleans)
*/
#ifndef CWIID_INTERNAL_H
#define CWIID_INTERNAL_H
#include <stdint.h>
#include <pthread.h>
#include <sys/types.h> /* ssize_t */
#include "cwiid.h"
/* Bluetooth magic numbers */
#define BT_TRANS_MASK 0xF0
#define BT_TRANS_HANDSHAKE 0x00
#define BT_TRANS_SET_REPORT 0x50
#define BT_TRANS_DATA 0xA0
#define BT_TRANS_DATAC 0xB0
#define BT_PARAM_MASK 0x0F
/* HANDSHAKE params */
#define BT_PARAM_SUCCESSFUL 0x00
#define BT_PARAM_NOT_READY 0x01
#define BT_PARAM_ERR_INVALID_REPORT_ID 0x02
#define BT_PARAM_ERR_UNSUPPORTED_REQUEST 0x03
#define BT_PARAM_ERR_INVALID_PARAMETER 0x04
#define BT_PARAM_ERR_UNKNOWN 0x0E
#define BT_PARAM_ERR_FATAL 0x0F
/* SET_REPORT, DATA, DATAC params */
#define BT_PARAM_INPUT 0x01
#define BT_PARAM_OUTPUT 0x02
#define BT_PARAM_FEATURE 0x03
/* Wiimote specific magic numbers */
#define WIIMOTE_NAME "Nintendo RVL-CNT-01"
#define WIIMOTE_CLASS_0 0x04
#define WIIMOTE_CLASS_1 0x25
#define WIIMOTE_CLASS_2 0x00
/* Wiimote port/channel/PSMs */
#define CTL_PSM 17
#define INT_PSM 19
/* Report numbers */
#define RPT_LED_RUMBLE 0x11
#define RPT_RPT_MODE 0x12
#define RPT_IR_ENABLE1 0x13
#define RPT_SPEAKER_ENABLE 0x14
#define RPT_STATUS_REQ 0x15
#define RPT_WRITE 0x16
#define RPT_READ_REQ 0x17
#define RPT_SPEAKER_DATA 0x18
#define RPT_SPEAKER_MUTE 0x19
#define RPT_IR_ENABLE2 0x1A
#define RPT_STATUS 0x20
#define RPT_READ_DATA 0x21
#define RPT_WRITE_ACK 0x22
#define RPT_BTN 0x30
#define RPT_BTN_ACC 0x31
#define RPT_BTN_EXT8 0x32
#define RPT_BTN_ACC_IR12 0x33
#define RPT_BTN_EXT19 0x34
#define RPT_BTN_ACC_EXT16 0x35
#define RPT_BTN_IR10_EXT9 0x36
#define RPT_BTN_ACC_IR10_EXT6 0x37
#define RPT_EXT21 0x3D
#define RPT_BTN_ACC_IR36_1 0x3E
#define RPT_BTN_ACC_IR36_2 0x3F
/* Button Mask (masks unknown bits in button bytes) */
#define BTN_MASK_0 0x1F
#define BTN_MASK_1 0x9F
#define NUNCHUK_BTN_MASK 0x03
/* Extension Values */
#define EXT_NONE 0x2E
#define EXT_PARTIAL 0xFF
#define EXT_NUNCHUK 0x00
#define EXT_CLASSIC 0x01
/* IR Enable blocks */
#define MARCAN_IR_BLOCK_1 "\x00\x00\x00\x00\x00\x00\x90\x00\xC0"
#define MARCAN_IR_BLOCK_2 "\x40\x00"
#define CLIFF_IR_BLOCK_1 "\x02\x00\x00\x71\x01\x00\xAA\x00\x64"
#define CLIFF_IR_BLOCK_2 "\x63\x03"
/* Extension Decode */
#define DECODE(a) (((a ^ 0x17)+0x17)&0xFF)
/* Write Sequences */
enum write_seq_type {
WRITE_SEQ_RPT,
WRITE_SEQ_MEM
};
/* send_report flags */
#define SEND_RPT_NO_RUMBLE 0x01
struct write_seq {
enum write_seq_type type;
uint32_t report_offset;
const void *data;
uint16_t len;
uint8_t flags;
};
#define SEQ_LEN(seq) (sizeof(seq)/sizeof(struct write_seq))
/* Message arrays */
struct mesg_array {
uint8_t count;
struct timespec timestamp;
union cwiid_mesg array[CWIID_MAX_MESG_COUNT];
};
/* RW State/Mesg */
enum rw_status {
RW_IDLE,
RW_READ,
RW_WRITE,
RW_CANCEL
};
struct rw_mesg {
enum rw_status type;
uint8_t error;
uint32_t offset;
uint8_t len;
char data[16];
};
/* Wiimote struct */
struct wiimote {
int flags;
int ctl_socket;
int int_socket;
pthread_t router_thread;
pthread_t status_thread;
pthread_t mesg_callback_thread;
int mesg_pipe[2];
int status_pipe[2];
int rw_pipe[2];
struct cwiid_state state;
enum rw_status rw_status;
cwiid_mesg_callback_t *mesg_callback;
pthread_mutex_t state_mutex;
pthread_mutex_t rw_mutex;
pthread_mutex_t rpt_mutex;
int id;
const void *data;
};
/* prototypes */
/* thread.c */
void *router_thread(struct wiimote *wiimote);
void *status_thread(struct wiimote *wiimote);
void *mesg_callback_thread(struct wiimote *wiimote);
/* util.c */
void cwiid_err(struct wiimote *wiimote, const char *str, ...);
int verify_handshake(struct wiimote *wiimote);
int send_report(struct wiimote *wiimote, uint8_t flags, uint8_t report,
size_t len, const void *data);
int exec_write_seq(struct wiimote *wiimote, unsigned int len,
struct write_seq *seq);
int full_read(int fd, void *buf, size_t len);
int write_mesg_array(struct wiimote *wiimote, struct mesg_array *ma);
int read_mesg_array(int fd, struct mesg_array *ma);
int cancel_rw(struct wiimote *wiimote);
int cancel_mesg_callback(struct wiimote *wiimote);
/* process.c */
int process_error(struct wiimote *, ssize_t, struct mesg_array *);
int process_status(struct wiimote *, const unsigned char *,
struct mesg_array *);
int process_btn(struct wiimote *, const unsigned char *, struct mesg_array *);
int process_acc(struct wiimote *, const unsigned char *, struct mesg_array *);
int process_ir10(struct wiimote *, const unsigned char *, struct mesg_array *);
int process_ir12(struct wiimote *, const unsigned char *, struct mesg_array *);
int process_ext(struct wiimote *, unsigned char *, unsigned char,
struct mesg_array *);
int process_read(struct wiimote *, unsigned char *);
int process_write(struct wiimote *, unsigned char *);
/* state.c */
int update_state(struct wiimote *wiimote, struct mesg_array *ma);
int update_rpt_mode(struct wiimote *wiimote, int8_t rpt_mode);
#endif
// ===================================================================
// 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)
// ChangeLog:
// 2009-06-09 DISIS (Michael Hawthorne <[email protected]> & Ivica Ico Bukvic <[email protected]>)
// http://disis.music.vt.edu
// * Bug-fixes (connecting and disconnecting crashes)
// * Multithreaded implementation to prevent wiimote from starving PD audio thread
// * Bang implementation to allow for better data rate control
// * Updated help file
// Changelog:
// 2009-10-05 DISIS (Ivica Ico Bukvic <[email protected]>)
// http://disis.music.vt.edu
// * Additional bug-fixes, code clean-up, and improvements
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
#include <bluetooth/bluetooth.h>
#include <m_pd.h>
#include <math.h>
#include <pthread.h>
#include "cwiid_internal.h"
#define PI 3.14159265358979323
#define DARWIN_CALIB
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;
int extensionAttached;
int mode; //0 = use metro for timer (default), 1 = send as fast as possible
//Creating separate threads for actions known to cause sample drop-outs
t_float rumble;
pthread_t rumble_t;
t_float led;
pthread_t led_t;
t_float connection;
pthread_t connection_t;
t_symbol *addr;
t_float rpt;
unsigned char rpt_mode;
pthread_t rpt_t;
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[1];
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_outlet *outlet_connected;
} 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 16
t_wiimote *g_wiimoteList[MAX_WIIMOTES];
// Structure to pass generic parameters into a threaded function.
// Added by VT DISIS
typedef struct
{
t_wiimote *wiimote;
t_floatarg f;
} threadedFunctionParams;
// ==============================================================
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);
if (x->toggle_acc) post("acceleration: ON");
else post("acceleration: OFF");
if (x->toggle_ir) post("IR: ON");
else post("IR: OFF");
if (x->toggle_nc) post("Nunchuck: ON");
else post("Nunchuck: 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)
{
//post("Buttons: %X %X", (mesg->buttons & 0xFF00)>>8, data->btn_data.buttons & 0x00FF);
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) {}
*/
}
// Records acceleration into wiimote object.
// To retrieve the information in pd, send a bang to input or change output mode to 1
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);
}
}
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);
}
}
}
}
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 (atom_getint(x->nc_btn_atoms) != mesg->buttons) {
SETFLOAT(x->nc_btn_atoms+0, mesg->buttons);
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);
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);
}
void cwiid_doBang(t_wiimote *x)
{
if (x->toggle_nc == 1 && x->extensionAttached == 1) {
outlet_anything(x->outlet_nc_stick, &s_list, 2, x->nc_stick_atoms);
outlet_anything(x->outlet_nc_acc, &s_list, 3, x->nc_acc_atoms);
}
if (x->toggle_ir == 1) outlet_anything(x->outlet_ir, &s_list, 4, x->ir_atoms);
if (x->toggle_acc == 1) outlet_anything(x->outlet_acc, &s_list, 3, x->acc_atoms);
}
void cwiid_pthread_setRumble(void *ptr)
{
threadedFunctionParams *rPars = (threadedFunctionParams*)ptr;
t_wiimote *x = rPars->wiimote;
t_floatarg f = rPars->f;
while(x->rumble > -1) {
if (f != x->rumble) {
f = x->rumble;
if (cwiid_command(x->wiimote, CWIID_CMD_RUMBLE, f)) {
//post("wiiremote error: problem setting rumble.");
}
} else {
usleep(10000);
}
}
pthread_exit(0);
}
void cwiid_setRumble(t_wiimote *x, t_floatarg f)
{
if (x->connected) {
x->rumble = f;
}
}
// 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 *wiimote, int mesg_count,
union cwiid_mesg mesg_array[], struct timespec *timestamp)
{
int i;
t_wiimote *x;
if (g_wiimoteList[wiimote->id] == NULL) {
post("no wiimote loaded: %d%",wiimote->id);
}
else if (x->connection == 2) {
x = g_wiimoteList[wiimote->id];
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");
x->extensionAttached = 0;
break;
case CWIID_EXT_NUNCHUK:
post("Nunchuck extension attached");
x->extensionAttached = 1;
#ifdef DARWIN_CALIB
x->nc_acc_zero.x = 128;
x->nc_acc_zero.y = 129;
x->nc_acc_zero.z = 128;
x->nc_acc_one.x = 153;
x->nc_acc_one.y = 154;
x->nc_acc_one.z = 154;
#else
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];
}
#endif
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;
}
}
if (x->mode == 1) {
cwiid_doBang(x);
}
}
}
// ==============================================================
void cwiid_pthread_setReportMode(void *ptr)
{
threadedFunctionParams *sPars = (threadedFunctionParams*)ptr;
t_wiimote *x = sPars->wiimote;
t_floatarg loc_rpt = 0;
unsigned char loc_rpt_mode;
while (x->rpt > -1) {
if (loc_rpt != x->rpt) {
loc_rpt = x->rpt;
loc_rpt_mode = CWIID_RPT_STATUS | CWIID_RPT_BTN;
if (x->toggle_ir) loc_rpt_mode |= CWIID_RPT_IR;
if (x->toggle_acc) loc_rpt_mode |= CWIID_RPT_ACC;
if (x->toggle_nc) loc_rpt_mode |= CWIID_RPT_EXT;
if (cwiid_command(x->wiimote, CWIID_CMD_RPT_MODE, loc_rpt_mode)) {
//post("wiimote error: problem setting report mode.");
}
}
else {
usleep(10000);
}
}
pthread_exit(0);
}
void cwiid_setReportMode(t_wiimote *x, t_floatarg r)
{
if (x->connected || x->connection == 3) {
if (r >= 0) x->rpt_mode = (unsigned char) r;
else {
x->rpt_mode = CWIID_RPT_STATUS | CWIID_RPT_BTN;
if (x->toggle_ir) x->rpt_mode |= CWIID_RPT_IR;
if (x->toggle_acc) x->rpt_mode |= CWIID_RPT_ACC;
if (x->toggle_nc) x->rpt_mode |= CWIID_RPT_EXT;
}
x->rpt += 1;
if (x->rpt > 1) x->rpt = 0;
}
}
void cwiid_setMode(t_wiimote *x, t_floatarg f)
{
if (f == 0) {
x->mode = 0;
post("setting metro output mode (default)");
}
else if (f == 1) {
x->mode = 1;
post("setting maximum output rate 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_pthread_setLED(void *ptr)
{
threadedFunctionParams *lPars = (threadedFunctionParams*)ptr;
t_wiimote *x = lPars->wiimote;
t_floatarg f = lPars->f;
while(x->led > -1) {
if (f != x->led) {
f = x->led;
// some possible values:
// CWIID_LED0_ON 0x01
// CWIID_LED1_ON 0x02
// CWIID_LED2_ON 0x04
// CWIID_LED3_ON 0x08
if (cwiid_command(x->wiimote, CWIID_CMD_LED, f)) {
//post("wiiremote error: problem setting LED.");
}
} else {
usleep(10000);
}
}
pthread_exit(0);
}
void cwiid_setLED(t_wiimote *x, t_floatarg f)
{
if (x->connected) {
x->led = f;
}
}
// 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_manageConnection(void *ptr)
{
threadedFunctionParams *rPars = (threadedFunctionParams*)ptr;
t_wiimote *x = rPars->wiimote;
t_floatarg f = rPars->f;
// -1 = free
// 0 = disconnected
// 1 = disconnecting
// 2 = connected
// 3 = connecting
while(x->connection > -1) {
if (f != x->connection) {
if (x->connection == 1) {
f = x->connection;
if (cwiid_close(x->wiimote)) {
//post("wiimote error: problems when disconnecting.");
}
else {
//post("disconnect successfull, resetting values");
g_wiimoteList[x->wiimoteID] = NULL;
x->connected = 0;
outlet_float(x->outlet_connected, x->connected);
//we have disconnected so make connection 0 and sync thread's f
x->connection = 0;
f = x->connection;
}
}
else if (x->connection == 3) {
f = x->connection;
int i;
bdaddr_t bdaddr;
// determine address:
if (x->addr==gensym("NULL")) {
//post("Searching automatically...");
bdaddr = *BDADDR_ANY;
}
else {
str2ba(x->addr->s_name, &bdaddr);
//post("Connecting to given address...");
//post("Press buttons 1 and 2 simultaneously.");
}
// bdaddr = *BDADDR_ANY;
// connect:
for (i=0;i<MAX_WIIMOTES;++i) {
if (g_wiimoteList[i]==NULL) {
//post("open: Connect wiimote %d",i);
x->wiimote = cwiid_open(&bdaddr,CWIID_FLAG_MESG_IFC);
x->wiimoteID = i;
if (x->wiimote) {
x->wiimote->id = i;
g_wiimoteList[i] = x;
}
break;
}
}
if (x->wiimote == NULL) {
//post("Error: could not find and/or connect to a wiimote. Please ensure that bluetooth is enabled, and that the 'hcitool scan' command lists your Nintendo device.");
//we have failed to connect so make connection 2 and sync thread's f
x->connection = 0;
f = x->connection;
} else {
//post("wiimote has successfully connected");
#ifdef DARWIN_CALIB
x->acc_zero.x = 128;
x->acc_zero.y = 129;
x->acc_zero.z = 128;
x->acc_one.x = 153;
x->acc_one.y = 154;
x->acc_one.z = 154;
#else
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]);
}
#endif
x->connected = 1;
cwiid_setReportMode(x,-1);
if (cwiid_set_mesg_callback(x->wiimote, &cwiid_callback)) {
//fprintf(stderr, "Unable to set message callback\n");
}
outlet_float(x->outlet_connected, x->connected);
// send brief rumble to acknowledge connect
// and give a bit of a wait before doing so
usleep(250000);
cwiid_setRumble(x, 1);
usleep(250000);
cwiid_setRumble(x, 0);
//we have connected so make connection 2 and sync thread's f
x->connection = 2;
f = x->connection;
}
}
} else {
usleep(10000);
}
}
pthread_exit(0);
}
void cwiid_doConnect(t_wiimote *x, t_symbol *addr)
{
if (!x->connected && x->connection != 3) {
x->addr = addr;
x->connection = 3;
}
}
// 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.
void cwiid_discover(t_wiimote *x)
{
if (!x->connected && x->connection != 3) {
post("Put the wiimote into discover mode by pressing buttons 1 and 2 simultaneously.");
cwiid_doConnect(x, gensym("NULL"));
}
else {
post("connect: device already connected!");
}
}
void cwiid_doDisconnect(t_wiimote *x)
{
if (x->connected && x->connection != 1)
{
x->connection = 1;
}
else post("disconnect: device is not connected!");
}
// ==============================================================
// ==============================================================
static void *cwiid_new(t_symbol* s, int argc, t_atom *argv)
{
post( "DISIS threaded implementation of wiimote object v.0.6.3");
//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);
// status outlet:
x->outlet_connected = outlet_new(&x->x_obj, &s_float);
// initialize toggles:
x->toggle_acc = 0;
x->toggle_ir = 0;
x->toggle_nc = 0;
// initialize values:
SETFLOAT(x->acc_atoms+0, 0);
SETFLOAT(x->acc_atoms+1, 0);
SETFLOAT(x->acc_atoms+2, 0);
SETFLOAT(x->ir_atoms+0, 0);
SETFLOAT(x->ir_atoms+1, 0);
SETFLOAT(x->ir_atoms+2, 0);
SETFLOAT(x->ir_atoms+3, 0);
SETFLOAT(x->nc_acc_atoms+0, 0);
SETFLOAT(x->nc_acc_atoms+1, 0);
SETFLOAT(x->nc_acc_atoms+2, 0);
x->connected = 0;
x->wiimoteID = -1;
x->extensionAttached = 0;
x->rumble = 0;
x->led = 0;
x->connection = 0; // -1 = free, 0 = disconnected, 1 = disconnecting, 2 = connected, 3 = connecting
x->addr = gensym("NULL");
x->rpt = 0;
x->rpt_mode = -1;
// spawn threads for actions known to cause sample drop-outs
threadedFunctionParams rPars;
rPars.wiimote = x;
rPars.f = 0;
pthread_create( &x->rpt_t, NULL, (void *) &cwiid_pthread_setReportMode, (void *) &rPars);
pthread_create( &x->rumble_t, NULL, (void *) &cwiid_pthread_setRumble, (void *) &rPars);
pthread_create( &x->led_t, NULL, (void *) &cwiid_pthread_setLED, (void *) &rPars);
pthread_create( &x->connection_t, NULL, (void *) &cwiid_manageConnection, (void *) &rPars);
post("setting metro output mode (default)");
x->mode = 0;
// 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, 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)
{
if (x->connected) {
cwiid_doDisconnect(x);
usleep(250000); //let the thread do its thing
}
x->rumble = -1;
x->led = -1;
x->connection = -1;
x->rpt = -1;
pthread_join(x->rpt_t, NULL);
pthread_join(x->rumble_t, NULL);
pthread_join(x->led_t, NULL);
pthread_join(x->connection_t, NULL);
}
void disis_wiimote_setup(void)
{
int i;
for (i=0; i<MAX_WIIMOTES; i++) g_wiimoteList[i] = NULL;
cwiid_class = class_new(gensym("disis_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, 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);
class_addbang(cwiid_class, cwiid_doBang);
class_addmethod(cwiid_class, (t_method) cwiid_setMode, gensym("mode"), A_DEFFLOAT, 0);
}
#N struct IR-blobs float x float y symbol s;
#N struct NC-stick float x float y symbol s;
#N canvas 118 47 881 512 10;
#X msg 19 322 disconnect;
#X obj 350 266 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X msg 60 95 discover;
#X msg 350 296 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 86 472 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 106 451 pd \$0-IR-stuff;
#X msg 478 313 setLED \$1;
#X obj 478 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 502 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 526 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 550 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 435 263 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 478 290 pd bytemask;
#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 127 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 60 492 pd \$0-button-stuff;
#X text 783 5 Buttons:;
#N canvas 185 133 481 416 NC-data 0;
#X scalar NC-stick 135 130 \;;
#X coords 0 0 256 256 80 80 1;
#X restore 681 534 pd NC-data;
#X obj 161 615 print;
#X msg 36 73 connect 00:1E:35:1D:0E:15;
#X obj 15 233 metro 100;
#X obj 15 203 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 37 251 Enable metro to get accelerometer uppdates;
#X text 37 262 (xyz wiimote \, xyz nunchuk \, ir);
#X text 38 272 Buttons do not require bang to be updated;
#X text 5 36 Threaded implementation of Wiimote by DISIS
<http://disis.music.vt.edu>
;
#X msg 306 394 mode \$1;
#X obj 306 364 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 304 425 0 (default) uses metro to initiate output;
#X text 304 437 1 outputs as fast as possible;
#X text 304 451 NB: buttons are independent from either;
#X text 304 411 mode of operation:;
#X text 328 462 mode offering highest resolution possible;
#X text 304 475 P.S. Running metro in mode 1;
#X text 333 486 is pretty much pointless;
#X obj 117 365 disis_wiimote;
#X obj 161 589 disis_wiimote 00:19:1D:BE:6A:66;
#X obj 249 340 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 230 364 connection;
#X text 235 374 indicator;
#X msg 19 299 debug;
#X connect 0 0 75 0;
#X connect 1 0 3 0;
#X connect 2 0 75 0;
#X connect 3 0 75 0;
#X connect 4 0 6 0;
#X connect 5 0 7 0;
#X connect 6 0 75 0;
#X connect 7 0 75 0;
#X connect 10 0 75 0;
#X connect 11 0 16 0;
#X connect 12 0 16 1;
#X connect 13 0 16 2;
#X connect 14 0 16 3;
#X connect 16 0 10 0;
#X connect 20 0 24 0;
#X connect 24 0 75 0;
#X connect 59 0 75 0;
#X connect 60 0 75 0;
#X connect 61 0 60 0;
#X connect 66 0 75 0;
#X connect 67 0 66 0;
#X connect 75 0 55 0;
#X connect 75 1 8 0;
#X connect 75 2 9 0;
#X connect 75 3 25 0;
#X connect 75 4 25 1;
#X connect 75 5 25 2;
#X connect 75 6 77 0;
#X connect 76 0 58 0;
#X connect 80 0 75 0;
NAME=disis_wiimote
SYM=disis_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=$(HOME)/pd/pd-0.40-0
PD_PATH=/home/hans/code/pure-data/trunk/pd
######################################################
# You shouldn't need to change anything beyond here! #
######################################################
ifdef PD_PATH
PD_INCLUDE := -I$(PD_PATH)/src
PD_EXTRA_PATH := $(PD_PATH)/extra
PD_DOC_PATH := $(PD_PATH)/doc
else
PD_INCLUDE := -I/usr/local/include
PD_EXTRA_PATH := /usr/local/lib/pd/extra
PD_DOC_PATH := /usr/local/lib/pd/doc
endif
# we just use the cwiid that comes with ubuntu/hardy
# although the code still uses the cwiid_internal.h from the
# supplied source
LIBS = -lcwiid -lbluetooth -lpthread
#LIBS = $(CWIID_PATH)/libcwiid/libcwiid.a -lrt -lbluetooth -lpthread
current: pd_linux
##### LINUX:
CWIID_INCLUDE = -I$(CWIID_PATH)/libcwiid
pd_linux: $(NAME).pd_linux
.SUFFIXES: .pd_linux
LINUXCFLAGS = -DPD -g -funroll-loops -fomit-frame-pointer \
-Wall -Wshadow -Wstrict-prototypes
.c.pd_linux:
cc $(LINUXCFLAGS) $(PD_INCLUDE) $(CWIID_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
_______________________________________________
[email protected] mailing list
UNSUBSCRIBE and account-management ->
http://lists.puredata.info/listinfo/pd-list