[PD-cvs] externals/io/wiiremote COPYRIGHT.txt, NONE, 1.1 Makefile, NONE, 1.1 aka.wiiremote.c, NONE, 1.1 wiiremote.c, NONE, 1.1 wiiremote.h, NONE, 1.1

Hans-Christoph Steiner eighthave at users.sourceforge.net
Sat Dec 16 23:03:45 CET 2006


Update of /cvsroot/pure-data/externals/io/wiiremote
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30283/io/wiiremote

Added Files:
	COPYRIGHT.txt Makefile aka.wiiremote.c wiiremote.c wiiremote.h 
Log Message:
first stab at porting the Max aka.wiiremote object.  it builds now, but I don't think it works

--- NEW FILE: COPYRIGHT.txt ---
Max porting by Masayuki Akamatsu
Copyright (c) 2006, Masayuki Akamatsu
Based on "DarwiinRemote" by Hiroaki Kimura
Copyright (c) 2006, Hiroaki Kimura
All rights reserved.

   Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- NEW FILE: wiiremote.c ---
// wiiremote.c
// Copyright by Masayuki Akamatsu
// Based on "DarwiinRemote" by Hiroaki Kimura

#include "wiiremote.h"

// this type is used a lot (data array):
typedef unsigned char darr[];

#define	kTrial	10

static	WiiRemoteRec	gWiiRemote;

//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------

WiiRemoteRef wiiremote_init(void)
{
	gWiiRemote.inquiry = nil;
	gWiiRemote.device = nil;
	gWiiRemote.ichan = nil;
	gWiiRemote.cchan = nil;
	
	gWiiRemote.accX = 0x10;
	gWiiRemote.accY = 0x10;
	gWiiRemote.accZ = 0x10;
	gWiiRemote.buttonData = 0;
	gWiiRemote.leftPoint = -1;
	gWiiRemote.tracking = false;
	
	gWiiRemote.batteryLevel = 0;
	
	gWiiRemote.isIRSensorEnabled = false;
	gWiiRemote.isMotionSensorEnabled = false;
	gWiiRemote.isVibrationEnabled = false;
	
	gWiiRemote.isExpansionPortUsed = false;
	gWiiRemote.isLED1Illuminated = false;
	gWiiRemote.isLED2Illuminated = false;
	gWiiRemote.isLED3Illuminated = false;
	gWiiRemote.isLED4Illuminated = false;
	
	return &gWiiRemote;
}

//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------

void checkDevice(IOBluetoothDeviceRef device)
{
	CFStringRef	myString;

	myString = IOBluetoothDeviceGetName(device);
	if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo)
	{
		gWiiRemote.device = IOBluetoothObjectRetain(device);
	}
}

IOBluetoothDeviceInquiryDeviceFoundCallback myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device)
{
	checkDevice(device);
}

IOBluetoothDeviceInquiryDeviceNameUpdatedCallback	myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining)
{
	checkDevice(device);
}

IOBluetoothDeviceInquiryCompleteCallback myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted)
{
	IOReturn				result;
	
	if (aborted) return; // called by stop ;)
	
	if (error != kIOReturnSuccess)
	{
		wiiremote_stopsearch();
		return;
	}
}

//--------------------------------------------------------------------------------------------

Boolean wiiremote_search(void)
{
	IOReturn	ret;
	
	if (gWiiRemote.inquiry != nil)
		return true;
	
	gWiiRemote.inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon(nil);
	IOBluetoothDeviceInquirySetDeviceFoundCallback(gWiiRemote.inquiry, myFoundFunc);
	IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(gWiiRemote.inquiry, myUpdatedFunc);
	IOBluetoothDeviceInquirySetCompleteCallback(gWiiRemote.inquiry, myCompleteFunc);

	ret = IOBluetoothDeviceInquiryStart(gWiiRemote.inquiry);
	if (ret != kIOReturnSuccess)
	{
		IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry);
		gWiiRemote.inquiry = nil;
		return false;
	}
	return true;
}

Boolean wiiremote_stopsearch(void)
{
	IOReturn	ret;

	if (gWiiRemote.inquiry == nil)
	{
		return true;	// already stopped
	}
	
	ret = IOBluetoothDeviceInquiryStop(gWiiRemote.inquiry);
	
	if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted)
	{
		// kIOReturnNotPermitted is if it's already stopped
	}
	
	IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry);
	gWiiRemote.inquiry = nil;
	
	return (ret==kIOReturnSuccess);
}

//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------

 IOBluetoothL2CAPChannelIncomingDataListener myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon)
{
	unsigned char *dp = (unsigned char*)data;

	 if (dp[1] == 0x20 && length >= 8)
	 {
		 gWiiRemote.batteryLevel = (double)dp[7];
		 gWiiRemote.batteryLevel /= (double)0xC0;
		 
		 gWiiRemote.isExpansionPortUsed =  (dp[4] & 0x02) != 0;
		 gWiiRemote.isLED1Illuminated = (dp[4] & 0x10) != 0;
		 gWiiRemote.isLED2Illuminated = (dp[4] & 0x20) != 0;
		 gWiiRemote.isLED3Illuminated = (dp[4] & 0x40) != 0;
		 gWiiRemote.isLED4Illuminated = (dp[4] & 0x80) != 0;
		 
		 //have to reset settings (vibration, motion, IR and so on...)
		 wiiremote_irsensor(gWiiRemote.isIRSensorEnabled);
	 }

	if ((dp[1]&0xF0) == 0x30)
	{
		gWiiRemote.buttonData = ((short)dp[2] << 8) + dp[3];
	 
		if (dp[1] & 0x01)
		{
			gWiiRemote.accX = dp[4];
			gWiiRemote.accY = dp[5];
			gWiiRemote.accZ = dp[6];
		 
			gWiiRemote.lowZ = gWiiRemote.lowZ * .9 + gWiiRemote.accZ * .1;
			gWiiRemote.lowX = gWiiRemote.lowX * .9 + gWiiRemote.accX * .1;
		 
			float absx = abs(gWiiRemote.lowX - 128);
			float absz = abs(gWiiRemote.lowZ - 128);
		 
			if (gWiiRemote.orientation == 0 || gWiiRemote.orientation == 2) absx -= 5;
			if (gWiiRemote.orientation == 1 || gWiiRemote.orientation == 3) absz -= 5;
		 
			if (absz >= absx)
			{
				if (absz > 5)
					gWiiRemote.orientation = (gWiiRemote.lowZ > 128) ? 0 : 2;
			}
			else
			{
				if (absx > 5)
					gWiiRemote.orientation = (gWiiRemote.lowX > 128) ? 3 : 1;
			}
			//printf("orientation: %d\n", orientation);
		}
	 
		if (dp[1] & 0x02)
		{
			int i;
			for(i=0 ; i<4 ; i++)
			{
				gWiiRemote.irData[i].x = dp[7 + 3*i];
				gWiiRemote.irData[i].y = dp[8 + 3*i];
				gWiiRemote.irData[i].s = dp[9 + 3*i];
				gWiiRemote.irData[i].x += (gWiiRemote.irData[i].s & 0x30) << 4;
				gWiiRemote.irData[i].y += (gWiiRemote.irData[i].s & 0xC0) << 2;
				gWiiRemote.irData[i].s &= 0x0F;
			} 
		}
	}

	float ox, oy;

	if (gWiiRemote.irData[0].s < 0x0F && gWiiRemote.irData[1].s < 0x0F)
	{
		int l = gWiiRemote.leftPoint, r;
		if (gWiiRemote.leftPoint == -1)
		{
			//	printf("Tracking.\n");
			switch (gWiiRemote.orientation)
			{
				case 0: l = (gWiiRemote.irData[0].x < gWiiRemote.irData[1].x) ? 0 : 1; break;
				case 1: l = (gWiiRemote.irData[0].y > gWiiRemote.irData[1].y) ? 0 : 1; break;
				case 2: l = (gWiiRemote.irData[0].x > gWiiRemote.irData[1].x) ? 0 : 1; break;
				case 3: l = (gWiiRemote.irData[0].y < gWiiRemote.irData[1].y) ? 0 : 1; break;
			}
			gWiiRemote.leftPoint = l;
		}
		
		r = 1-l;
	 
		float dx = gWiiRemote.irData[r].x - gWiiRemote.irData[l].x;
		float dy = gWiiRemote.irData[r].y - gWiiRemote.irData[l].y;
	 
		float d = sqrt(dx*dx+dy*dy);
	 
		dx /= d;
		dy /= d;
	 
		float cx = (gWiiRemote.irData[l].x+gWiiRemote.irData[r].x)/1024.0 - 1;
		float cy = (gWiiRemote.irData[l].y+gWiiRemote.irData[r].y)/1024.0 - .75;
	 
		gWiiRemote.angle = atan2(dy, dx);
	 
		ox = -dy*cy-dx*cx;
		oy = -dx*cy+dy*cx;
		//printf("x:%5.2f;  y: %5.2f;  angle: %5.1f\n", ox, oy, angle*180/M_PI);
		
		gWiiRemote.tracking = true;
	}
	else
	{
		//	printf("Not tracking.\n");
		ox = oy = -100;
		gWiiRemote.leftPoint = -1;
		gWiiRemote.tracking = false;
	}
	
	gWiiRemote.posX = ox;	
	gWiiRemote.posY = oy;
}

IOBluetoothL2CAPChannelIncomingEventListener myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event)
{
	switch (event->eventType)
	{
		case kIOBluetoothL2CAPChannelEventTypeData:
			// In thise case:
			// event->u.newData.dataPtr  is a pointer to the block of data received.
			// event->u.newData.dataSize is the size of the block of data.
			myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon);
			break;
			
		case kIOBluetoothL2CAPChannelEventTypeClosed:
			// In this case:
			// event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel
			// object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below).
			break;
	}
}

IOBluetoothUserNotificationCallback myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef)
{
	wiiremote_disconnect();
}

//--------------------------------------------------------------------------------------------

Boolean wiiremote_connect(void)
{
	IOReturn	result;
	short		i;
	
	if (gWiiRemote.device == nil)
		return false;
	
	// connect the device
	for (i=0; i<kTrial; i++)
	{
		if (IOBluetoothDeviceOpenConnection(gWiiRemote.device, nil, nil) == kIOReturnSuccess)
			break;
		usleep(10000); //  wait 10ms
	}
	if (i==kTrial)	return false;
	
	gWiiRemote.disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(gWiiRemote.device, myDisconnectedFunc, 0);
	
	// performs an SDP query
	for (i=0; i<kTrial; i++)
	{
		if (IOBluetoothDevicePerformSDPQuery(gWiiRemote.device, nil, nil) == kIOReturnSuccess)
			break;
		usleep(10000); //  wait 10ms
	}
	if (i==kTrial)	return false;
	
	// open L2CAPChannel : BluetoothL2CAPPSM = 17
	for (i=0; i<kTrial; i++)
	{
		if (IOBluetoothDeviceOpenL2CAPChannelSync(gWiiRemote.device, &(gWiiRemote.cchan), 17, myEventListener, nil) == kIOReturnSuccess)
			break;
		usleep(10000); //  wait 10ms
	}
	if (i==kTrial)
	{
		gWiiRemote.cchan = nil;
		IOBluetoothDeviceCloseConnection(gWiiRemote.device);
		return false;
	}
	
	// open L2CAPChannel : BluetoothL2CAPPSM = 19
	for (i=0; i<kTrial; i++)
	{
		if (IOBluetoothDeviceOpenL2CAPChannelSync(gWiiRemote.device, &(gWiiRemote.ichan), 19, myEventListener, nil) == kIOReturnSuccess)
			break;
		usleep(10000); //  wait 10ms
	}
	if (i==kTrial)
	{
		gWiiRemote.ichan = nil;
		IOBluetoothL2CAPChannelCloseChannel(gWiiRemote.cchan);
		IOBluetoothDeviceCloseConnection(gWiiRemote.device);
		return false;
	}

	wiiremote_motionsensor(true);
	wiiremote_irsensor(false);
	wiiremote_vibration(false);
	wiiremote_led(false, false, false, false);
	
	return true;
}


Boolean wiiremote_disconnect(void)
{
	short	i;
	
	if (gWiiRemote.disconnectNotification != nil)
	{
		IOBluetoothUserNotificationUnregister(gWiiRemote.disconnectNotification);
		gWiiRemote.disconnectNotification = nil;
	}
	
	if (gWiiRemote.cchan && IOBluetoothDeviceIsConnected(gWiiRemote.device))
	{
		for (i=0; i<kTrial; i++)
		{
			if (IOBluetoothL2CAPChannelCloseChannel(gWiiRemote.cchan) == kIOReturnSuccess)
			{
				gWiiRemote.cchan = nil;
				break;
			}
		}
		if (i==kTrial)	return false;
	}
	
	if (gWiiRemote.ichan && IOBluetoothDeviceIsConnected(gWiiRemote.device))
	{
		for (i=0; i<kTrial; i++)
		{
			if (IOBluetoothL2CAPChannelCloseChannel(gWiiRemote.ichan) == kIOReturnSuccess)
			{
				gWiiRemote.ichan = nil;
				break;
			}
		}
		if (i==kTrial)	return false;
	}
	
	if (gWiiRemote.device && IOBluetoothDeviceIsConnected(gWiiRemote.device))
	{
		for (i=0; i<kTrial; i++)
		{
			if (IOBluetoothDeviceCloseConnection(gWiiRemote.device) == kIOReturnSuccess)
			{
				gWiiRemote.device = nil;
				break;
			}
		}
		if (i==kTrial)	return false;
	}
		
	return true;
}

//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------

Boolean sendCommand(unsigned char *data, size_t length)
{
	unsigned char buf[40];
	IOReturn	ret;
	int			i;
	
	memset(buf,0,40);
	buf[0] = 0x52;
	memcpy(buf+1, data, length);
	if (buf[1] == 0x16)
		length=23;
	else
		length++;
	
	for (i = 0; i<kTrial; i++)
	{
		ret = IOBluetoothL2CAPChannelWriteSync(gWiiRemote.cchan, buf, length);
		if (ret == kIOReturnSuccess)
			break;
		usleep(10000);
	}	
	
	return (ret==kIOReturnSuccess);
}

Boolean	writeData(const unsigned char *data, unsigned long address, size_t length)
{
	unsigned char cmd[22];
	int i;

	for(i=0 ; i<length ; i++) cmd[i+6] = data[i];
	
	for(;i<16 ; i++) cmd[i+6]= 0;
	
	cmd[0] = 0x16;
	cmd[1] = (address>>24) & 0xFF;
	cmd[2] = (address>>16) & 0xFF;
	cmd[3] = (address>> 8) & 0xFF;
	cmd[4] = (address>> 0) & 0xFF;
	cmd[5] = length;

	// and of course the vibration flag, as usual
	if (gWiiRemote.isVibrationEnabled)	cmd[1] |= 0x01;
	
	data = cmd;
	
	return sendCommand(cmd, 22);
}

//--------------------------------------------------------------------------------------------

Boolean wiiremote_motionsensor(Boolean enabled)
{
	gWiiRemote.isMotionSensorEnabled = enabled;

	unsigned char cmd[] = {0x12, 0x00, 0x30};
	if (gWiiRemote.isVibrationEnabled)		cmd[1] |= 0x01;
	if (gWiiRemote.isMotionSensorEnabled)	cmd[2] |= 0x01;
	if (gWiiRemote.isIRSensorEnabled)		cmd[2] |= 0x02;
	
	return sendCommand(cmd, 3);
}

Boolean wiiremote_irsensor(Boolean enabled)
{
	IOReturn ret;
	
	gWiiRemote.isIRSensorEnabled = enabled;
	
	// set register 0x12 (report type)
	if (ret = wiiremote_motionsensor(gWiiRemote.isMotionSensorEnabled)) return ret;
	
	// set register 0x13 (ir enable/vibe)
	if (ret = wiiremote_vibration(gWiiRemote.isVibrationEnabled)) return ret;
	
	// set register 0x1a (ir enable 2)
	unsigned char cmd[] = {0x1a, 0x00};
	if (enabled)	cmd[1] |= 0x04;
	if (ret = sendCommand(cmd, 2)) return ret;
	
	if(enabled){
		// based on marcan's method, found on wiili wiki:
		// tweaked to include some aspects of cliff's setup procedure in the hopes
		// of it actually turning on 100% of the time (was seeing 30-40% failure rate before)
		// the sleeps help it it seems
		usleep(10000);
		if (ret = writeData((darr){0x01}, 0x04B00030, 1)) return ret;
		usleep(10000);
		if (ret = writeData((darr){0x08}, 0x04B00030, 1)) return ret;
		usleep(10000);
		if (ret = writeData((darr){0x90}, 0x04B00006, 1)) return ret;
		usleep(10000);
		if (ret = writeData((darr){0xC0}, 0x04B00008, 1)) return ret;
		usleep(10000);
		if (ret = writeData((darr){0x40}, 0x04B0001A, 1)) return ret;
		usleep(10000);
		if (ret = writeData((darr){0x33}, 0x04B00033, 1)) return ret;
		usleep(10000);
		if (ret = writeData((darr){0x08}, 0x04B00030, 1)) return ret;
		
	}else{
		// probably should do some writes to power down the camera, save battery
		// but don't know how yet.
		
		//bug fix #1614587 
		wiiremote_motionsensor(gWiiRemote.isMotionSensorEnabled);
		wiiremote_vibration(gWiiRemote.isVibrationEnabled);
	}
	
	return true;
}

Boolean wiiremote_vibration(Boolean enabled)
{
	
	gWiiRemote.isVibrationEnabled = enabled;
	
	unsigned char cmd[] = {0x13, 0x00};
	if (gWiiRemote.isVibrationEnabled)	cmd[1] |= 0x01;
	if (gWiiRemote.isIRSensorEnabled)	cmd[1] |= 0x04;
	
	return sendCommand(cmd, 2);;
}

Boolean wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4)
{
	unsigned char cmd[] = {0x11, 0x00};
	if (gWiiRemote.isVibrationEnabled)	cmd[1] |= 0x01;
	if (enabled1)	cmd[1] |= 0x10;
	if (enabled2)	cmd[1] |= 0x20;
	if (enabled3)	cmd[1] |= 0x40;
	if (enabled4)	cmd[1] |= 0x80;
	
	gWiiRemote.isLED1Illuminated = enabled1;
	gWiiRemote.isLED2Illuminated = enabled2;
	gWiiRemote.isLED3Illuminated = enabled3;
	gWiiRemote.isLED4Illuminated = enabled4;
	
	return sendCommand(cmd, 2);
}

void wiiremote_getstatus(void)
{
	unsigned char cmd[] = {0x15, 0x00};
	sendCommand(cmd, 2);
}



--- NEW FILE: wiiremote.h ---
// wiiremote.h
// Copyright by Masayuki Akamatsu
// Based on "DarwiinRemote" by Hiroaki Kimura

#include <CoreFoundation/CoreFoundation.h>
#include <IOBluetooth/Bluetooth.h>
#include <IOBluetooth/IOBluetoothUserLib.h>

#include <stdio.h>
#include <string.h>

typedef struct {
	int x, y, s;
} IRData;

typedef struct _WiiRemoteRec
{
	IOBluetoothDeviceInquiryRef	inquiry;
	IOBluetoothDeviceRef		device;
	IOBluetoothL2CAPChannelRef	ichan;
	IOBluetoothL2CAPChannelRef	cchan;

	unsigned char	accX;
	unsigned char	accY;
	unsigned char	accZ;
	unsigned short	buttonData;
	
	float			lowZ;
	float			lowX;
	int				orientation;
	int				leftPoint; // is point 0 or 1 on the left. -1 when not tracking.
	float			posX;
	float			posY;
	float			angle;
	Boolean			tracking;

	IRData			irData[4];
	double			batteryLevel;
	
	Boolean			isIRSensorEnabled;
	Boolean			isMotionSensorEnabled;
	Boolean			isVibrationEnabled;
	
	Boolean			isExpansionPortUsed;
	Boolean			isLED1Illuminated;
	Boolean			isLED2Illuminated;
	Boolean			isLED3Illuminated;
	Boolean			isLED4Illuminated;
	
	IOBluetoothUserNotificationCallback	*disconnectNotification;
}	WiiRemoteRec, *WiiRemoteRef;

WiiRemoteRef	wiiremote_init(void);
Boolean			wiiremote_search(void);
Boolean			wiiremote_stopsearch(void);
Boolean			wiiremote_connect(void);
Boolean			wiiremote_disconnect(void);
Boolean			wiiremote_motionsensor(Boolean enabled);
Boolean			wiiremote_irsensor(Boolean enabled);
Boolean			wiiremote_vibration(Boolean enabled);
Boolean			wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4);
void			wiiremote_getstatus(void);

--- NEW FILE: Makefile ---
TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|')
EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|')

default: 
	make -C $(EXTERNALS_ROOT) $(TARGET)

install:
	make -C $(EXTERNALS_ROOT) $(TARGET)_install

clean:
	make -C $(EXTERNALS_ROOT) $(TARGET)_clean

test_locations:
	make -C $(EXTERNALS_ROOT) test_locations

# for emacs
etags:
	etags ../../../pd/src/*.h *.[ch] linux/input.h 
	make etags_`uname -s`

etags_Darwin:
	etags -a HID\ Utilities\ Source/*.[ch] \
		/System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \
		/System/Library/Frameworks/Carbon.framework/Headers/*.h  \
		/System/Library/Frameworks/IOKit.framework/Headers/hid*/*.[ch]

etags_Linux:
	etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h

etags_MINGW:
	etags -a /usr/include/*.h /usr/include/sys/*.h \
		/usr/local/include/*.h /usr/local/include/sys/*.h

--- NEW FILE: aka.wiiremote.c ---
// aka.wiiremote.c
// Copyright by Masayuki Akamatsu
// port to Pd by Hans-Christoph Steiner <hans at at.or.at>


#ifdef PD
#include "m_pd.h"
#define SETLONG SETFLOAT
static t_class *wiiremote_class;
#else /* Max */
#include "ext.h"
#endif
#include "wiiremote.h"

#define kInterval	100
#define	kMaxTrial	100


typedef struct _akawiiremote
{
#ifdef PD
	t_object        x_obj;
#else /* Max */
	struct object	obj;
#endif
	
	WiiRemoteRef	wiiremote;
	
	void			*clock;
	long			interval;
	long			trial;

	void			*statusOut;
	void			*buttonsOut;
	void			*irOut;
	void			*accOut;
} t_akawiiremote;

void *akawiiremote_class;	// the number of instance of this object

short	akawiiremote_count;

void akawiiremote_bang(t_akawiiremote *x);
void akawiiremote_connect(t_akawiiremote *x);
void akawiiremote_disconnect(t_akawiiremote *x);
void akawiiremote_motionsensor(t_akawiiremote *x, long enable);
void akawiiremote_irsensor(t_akawiiremote *x, long enable);
void akawiiremote_vibration(t_akawiiremote *x, long enable);
void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4);

void akawiiremote_getbatterylevel(t_akawiiremote *x);
void akawiiremote_getexpansionstatus(t_akawiiremote *x);
void akawiiremote_getledstatus(t_akawiiremote *x);

void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s);
void akawiiremote_clock(t_akawiiremote *x);
void *akawiiremote_new(t_symbol *s, short ac, t_atom *av);
void akawiiremote_free(t_akawiiremote *x);

#ifdef PD
void wiiremote_setup()
{
	wiiremote_class = class_new(gensym("wiiremote"), 
								 (t_newmethod)akawiiremote_new, 
								 (t_method)akawiiremote_free,
								 sizeof(t_akawiiremote),
								 CLASS_DEFAULT,
								 A_GIMME,0);

	class_addbang(wiiremote_class,(t_method)akawiiremote_bang);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);

	class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0);
	class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0);
	
	class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0);
	
	post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu");
	post("\tPd port by Hans-Christoph Steiner");
	
	akawiiremote_count = 0;
}
#else /* Max */
void main()
{
	setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0);

	addbang((method)akawiiremote_bang);
	addmess((method)akawiiremote_connect,"connect",0);
	addmess((method)akawiiremote_disconnect,"disconnect",0);
	addmess((method)akawiiremote_motionsensor,"motionsensor", A_DEFLONG, 0);
	addmess((method)akawiiremote_irsensor,"irsensor", A_DEFLONG, 0);
	addmess((method)akawiiremote_vibration,"vibration", A_DEFLONG, 0);
	addmess((method)akawiiremote_led,"led", A_DEFLONG, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0);

	addmess((method)akawiiremote_getbatterylevel,"getbatterylevel",0);
	addmess((method)akawiiremote_getexpansionstatus,"getexpansionstatus",0);
	addmess((method)akawiiremote_getledstatus,"getledstatus",0);
	
	addmess((method)akawiiremote_assist,"assist",A_CANT,0);
	
	post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu");
	
	akawiiremote_count = 0;
}
#endif /* PD */
//--------------------------------------------------------------------------------------------

void akawiiremote_bang(t_akawiiremote *x)
{
	t_atom list[4]; 
	
	if (x->wiiremote->device == nil)
		return;	// do nothing

#ifdef PD
	outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData);

	if (x->wiiremote->isIRSensorEnabled)
	{
		SETFLOAT(list,     x->wiiremote->posX);
		SETFLOAT(list + 1, x->wiiremote->posY);
		SETFLOAT(list + 2, x->wiiremote->angle);
		SETFLOAT (list + 3, x->wiiremote->tracking);
		outlet_list(x->irOut, &s_list, 4, list); 
	}

	if (x->wiiremote->isMotionSensorEnabled)
	{
		SETFLOAT(list,     x->wiiremote->accX);
		SETFLOAT(list + 1, x->wiiremote->accY);
		SETFLOAT(list + 2, x->wiiremote->accZ);
		SETFLOAT(list + 3, x->wiiremote->orientation);
		outlet_list(x->accOut, &s_list, 4, list); 
	}
#else /* Max */	
	outlet_int(x->buttonsOut, x->wiiremote->buttonData);

	if (x->wiiremote->isIRSensorEnabled)
	{
		SETFLOAT(list,     x->wiiremote->posX);
		SETFLOAT(list + 1, x->wiiremote->posY);
		SETFLOAT(list + 2, x->wiiremote->angle);
		SETLONG (list + 3, x->wiiremote->tracking);
		outlet_list(x->irOut, 0L, 4, &list); 
	}

	if (x->wiiremote->isMotionSensorEnabled)
	{
		SETLONG(list,     x->wiiremote->accX);
		SETLONG(list + 1, x->wiiremote->accY);
		SETLONG(list + 2, x->wiiremote->accZ);
		SETLONG(list + 3, x->wiiremote->orientation);
		outlet_list(x->accOut, 0L, 4, &list); 
	}
#endif /* PD */
	
	wiiremote_getstatus();
}

void akawiiremote_connect(t_akawiiremote *x)
{
	if (x->wiiremote->device == nil)	// if not connected
	{
		if (x->wiiremote->inquiry == nil)	// if not seatching
		{
			Boolean	result;

			result = wiiremote_search();	// start searching the device
			x->trial = 0;
			clock_delay(x->clock, 0); // start clock to check the device found
		}
	}
	else	// if already connected
	{
		t_atom	status;

		SETLONG(&status, 1);
		outlet_anything(x->statusOut, gensym("connect"), 1, &status);
	}
}

void akawiiremote_disconnect(t_akawiiremote *x)
{
	Boolean	result;
	t_atom	status;
	
	result = wiiremote_disconnect();
	SETLONG(&status, result);
	outlet_anything(x->statusOut, gensym("disconnect"), 1, &status);		
}

void akawiiremote_motionsensor(t_akawiiremote *x, long enable)
{
	wiiremote_motionsensor(enable);
}

void akawiiremote_irsensor(t_akawiiremote *x, long enable)
{
	wiiremote_irsensor(enable);
}

void akawiiremote_vibration(t_akawiiremote *x, long enable)
{
	wiiremote_vibration(enable);
}

void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4)
{
	wiiremote_led(enable1, enable2, enable3, enable4);
}

//--------------------------------------------------------------------------------------------

void akawiiremote_getbatterylevel(t_akawiiremote *x)
{
	t_atom	status;

	SETFLOAT(&status, x->wiiremote->batteryLevel);
	outlet_anything(x->statusOut, gensym("batterylevel"), 1, &status);		
}

void akawiiremote_getexpansionstatus(t_akawiiremote *x)
{
	t_atom	status;
	
	SETLONG(&status, x->wiiremote->isExpansionPortUsed);
	outlet_anything(x->statusOut, gensym("expansionstatus"), 1, &status);		
}

void akawiiremote_getledstatus(t_akawiiremote *x)
{
	t_atom list[4]; 
	
	SETLONG(list,     x->wiiremote->isLED1Illuminated);
	SETLONG(list + 1, x->wiiremote->isLED2Illuminated);
	SETLONG(list + 2, x->wiiremote->isLED3Illuminated);
	SETLONG(list + 3, x->wiiremote->isLED4Illuminated);
#ifdef PD
	outlet_anything(x->statusOut, gensym("ledstatus"), 4, list);
#else /* Max */
	outlet_anything(x->statusOut, gensym("ledstatus"), 4, &list);
#endif
}

//--------------------------------------------------------------------------------------------

void akawiiremote_clock(t_akawiiremote *x)
{
	Boolean	result;
	t_atom	status;
	
	if (x->wiiremote->device != nil)	// if the device is found...
	{
		clock_unset(x->clock);			// stop clock

		wiiremote_stopsearch();
		result = wiiremote_connect();	// connect to it
		SETLONG(&status, result);
		outlet_anything(x->statusOut, gensym("connect"), 1, &status);
	}
	else	// if the device is not found...
	{
		x->trial++;
		//SETLONG(&status, x->trial);
		//outlet_anything(x->statusOut, gensym("searching"), 1, &status);

		if (x->trial >= kMaxTrial)		// if trial is over
		{
			clock_unset(x->clock);		// stop clock

			wiiremote_stopsearch();
			SETLONG(&status, 0);
			outlet_anything(x->statusOut, gensym("connect"), 1, &status);
		}
		else
		{
			//post("trial %d",x->trial);
			clock_delay(x->clock, x->interval);	// restart clock
		}
	}
}

//--------------------------------------------------------------------------------------------

void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s)
{
#ifndef PD /* Max */
	if (m==ASSIST_INLET)
	{
		sprintf(s,"connect, bang, disconnect....");
	}
	else  
#endif /* NOT PD */
	{
		switch(a)
		{
			case 0: sprintf(s,"list(acc-x acc-y acc-z orientation)"); break;
			case 1: sprintf(s,"list(pos-x pos-y angle tracking)"); break;
			case 2: sprintf(s,"int(buttons)"); break;
			case 3: sprintf(s,"message(status)"); break;
		}
	}
}

//--------------------------------------------------------------------------------------------

void *akawiiremote_new(t_symbol *s, short ac, t_atom *av)
{
#ifdef PD
	t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class);
	
	x->clock = clock_new(x, (t_method)akawiiremote_clock);

	/* create anything outlet used for HID data */ 
	x->statusOut = outlet_new(&x->x_obj, 0);
	x->buttonsOut = outlet_new(&x->x_obj, &s_float);
	x->irOut = outlet_new(&x->x_obj, &s_list);
	x->accOut = outlet_new(&x->x_obj, &s_list);
#else /* Max */	
	t_akawiiremote *x;

	x = (t_akawiiremote *)newobject(akawiiremote_class);
	
	x->wiiremote = wiiremote_init();
	
	x->clock = clock_new(x, (method)akawiiremote_clock);

	x->statusOut = outlet_new(x, 0);
	x->buttonsOut = intout(x);
	x->irOut = listout(x);
	x->accOut = listout(x);
#endif /* PD */
	x->trial = 0;
	x->interval	= kInterval;
	

	akawiiremote_count++;
	return x;
}

void akawiiremote_free(t_akawiiremote *x)
{
	akawiiremote_count--;
	if (akawiiremote_count == 0)
		wiiremote_disconnect();

#ifdef PD
	if (x->clock)
		clock_unset(x->clock);
	clock_free(x->clock);
#else /* Max */	
	freeobject(x->clock); 
#endif
}






More information about the Pd-cvs mailing list