PageRenderTime 81ms CodeModel.GetById 1ms app.highlight 75ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ois/src/win32/extras/WiiMote/wiimote.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 794 lines | 627 code | 122 blank | 45 comment | 102 complexity | e9b1a515af261c7cecfc09873ec7cdc3 MD5 | raw file
  1#include "OISConfig.h"
  2#ifdef OIS_WIN32_WIIMOTE_SUPPORT
  3//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
  4//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
  5
  6//Edited for Toshiba Stack support (hopefully also all others) by 
  7//Sean Stellingwerff (http://sean.stellingwerff.com) using information
  8//gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D) 
  9
 10//#include "stdafx.h"
 11#include "wiimote.h"
 12#include <stdio.h>
 13
 14//output channels
 15const unsigned char OUTPUT_CHANNEL_FORCE_FEEDBACK = 0x13;
 16const unsigned char OUTPUT_CHANNEL_LED = 0x11;
 17const unsigned char OUTPUT_CHANNEL_REPORT = 0x12;
 18const unsigned char OUTPUT_READ_MEMORY = 0x17;
 19const unsigned char OUTPUT_WRITE_MEMORY = 0x16;
 20
 21const unsigned char OUTPUT_ENABLE_IR = 0x13;
 22const unsigned char OUTPUT_ENABLE_IR2 = 0x1a;
 23
 24//report request types
 25const unsigned char REQUEST_CONTINUOUS_REPORTS = 0x4;
 26const unsigned char REQUEST_SINGLE_REPORTS = 0x0;
 27
 28//input channels
 29const unsigned char INPUT_CHANNEL_BUTTONS_ONLY = 0x30;
 30const unsigned char INPUT_CHANNEL_BUTTONS_MOTION = 0x31;
 31const unsigned char INPUT_CHANNEL_WRITE_CONFIRM = 0x22;
 32const unsigned char INPUT_CHANNEL_EXPANSION_PORT = 0x20;
 33
 34const unsigned char INPUT_CHANNEL_MOTION_IR = 0x33;
 35const unsigned char INPUT_CHANNEL_MOTION_CHUCK_IR = 0x37;
 36const unsigned char INPUT_CHANNEL_MOTION_CHUCK = 0x35;
 37
 38//the ID values for a wiimote
 39const unsigned short mVendorID = 0x057E;
 40const unsigned short mDeviceID = 0x0306;
 41
 42//how to find the calibration data for the wiimote
 43const unsigned short CALIBRATION_ADDRESS = 0x16;
 44const unsigned short CALIBRATION_DATA_LENGTH = 7;
 45
 46//nunchuck constants
 47const unsigned long NUNCHUCK_STATUS_ADDRESS = 0x04A40000;
 48const unsigned long NUNCHUCK_CALIBRATION_ADDRESS = 0x04A40020;
 49const unsigned long NUNCHUCK_CALIBRATION_ADDRESS_2 = 0x04A40030;
 50const unsigned long NUNCHUCK_INIT_ADDRESS= 0x04A40040;
 51const unsigned long NUNCHUK_ID_ADDRESS = 0x04a400f0;
 52const unsigned char NUNCHUCK_INIT_VAL= 0x0;
 53
 54//IR constants
 55const unsigned long IR_REG_1 = 0x04b00030;
 56const unsigned long IR_REG_2 = 0x04b00033;
 57const unsigned long IR_SENS_ADDR_1 = 0x04b00000;
 58const unsigned long IR_SENS_ADDR_2 = 0x04b0001a;
 59
 60const unsigned char IR_SENS_MIDRANGE_PART1[] = {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64};
 61const unsigned char IR_SENS_MIDRANGE_PART2[] = {0x63, 0x03};
 62
 63const unsigned char IR_MODE_OFF = 0;
 64const unsigned char IR_MODE_STD = 1;
 65const unsigned char IR_MODE_EXP = 3;
 66const unsigned char IR_MODE_FULL = 5;
 67
 68cWiiMote::cWiiMote()
 69{
 70	Init();
 71}
 72
 73cWiiMote::~cWiiMote()
 74{
 75	Disconnect();
 76}
 77
 78void cWiiMote::Init()
 79{
 80	mReportMode = REPORT_MODE_EVENT_BUTTONS;
 81	mLastButtonStatus.Init();
 82	mLastExpansionReport.Init();
 83	mLastMotionReport.Init();
 84	mOutputControls.Init();
 85	mReadInfo.Init();
 86	mAccelCalibrationData.Init();
 87	mNunchuckAccelCalibrationData.Init();
 88	mNunchuckStickCalibrationData.Init();
 89	mLastIRReport.Init();
 90	mNunchuckAttached = false;
 91	mIRRunning = false;
 92	mDataStreamRunning = false;
 93}
 94
 95bool cWiiMote::SetReportMode(eReportMode mode)
 96{
 97	mReportMode = mode;
 98	return SendReportMode();
 99}
100
101bool cWiiMote::SendReportMode()
102{
103	bool continuous = true;
104	unsigned char channel = INPUT_CHANNEL_BUTTONS_ONLY;
105	bool check_chuck = false;
106	
107	switch (mReportMode)
108	{
109	case REPORT_MODE_MOTION_IR:
110		channel = INPUT_CHANNEL_MOTION_IR;
111		break;
112	case REPORT_MODE_MOTION_CHUCK_IR:
113		channel = INPUT_CHANNEL_MOTION_CHUCK_IR;
114		check_chuck = true;
115		break;
116	case REPORT_MODE_MOTION_CHUCK:
117		channel = INPUT_CHANNEL_MOTION_CHUCK;
118		check_chuck = true;
119		break;
120	case REPORT_MODE_MOTION:
121		channel = INPUT_CHANNEL_BUTTONS_MOTION;
122		break;
123	case REPORT_MODE_EVENT_BUTTONS:
124		channel = INPUT_CHANNEL_BUTTONS_ONLY;
125		continuous = false;
126		break;
127	default:
128		break;
129	}
130
131	//check to make sure that there is a chuck attached
132//	if (check_chuck && !mNunchuckAttached)
133//	{
134//		printf("Supposed to check for nunchuck, but couldn't find one!");
135//		return false;
136//	}
137
138	bool retval = SelectInputChannel(continuous,channel);
139	return retval;
140}
141
142bool cWiiMote::ConnectToDevice(int index)
143{
144	Init();
145	const bool retval = mHIDDevice.Connect(mDeviceID,mVendorID,index) && 
146						SetReportMode(REPORT_MODE_MOTION_CHUCK_IR) && 
147						UpdateOutput() &&
148						ReadCalibrationData();
149
150	if (retval)
151	{
152		InitNunchuck();
153	}
154	return retval;
155}
156
157bool cWiiMote::Disconnect()
158{
159	bool retval = false;
160	StopDataStream();
161	
162	if (mHIDDevice.IsConnected())
163	{
164		retval = mHIDDevice.Disconnect();
165	}
166
167	return retval;
168}
169
170bool cWiiMote::SetVibration(bool vib_on)
171{
172	bool retval = true;
173	if (mOutputControls.mVibration != vib_on)
174	{
175		mOutputControls.mVibration = vib_on;
176		retval = UpdateOutput();
177	}
178	return retval;
179}
180
181void cWiiMote::ClearBuffer()
182{
183	memset(mOutputBuffer,0, mOutputBufferSize);
184}
185
186bool cWiiMote::SetLEDs(bool led1, bool led2, bool led3, bool led4)
187{
188	const bool no_change = mOutputControls.mLED1 == led1 &&
189							mOutputControls.mLED2 == led2 &&
190							mOutputControls.mLED3 == led3 &&
191							mOutputControls.mLED4 == led4;
192
193	if (no_change)
194	{
195		return true;
196	}
197
198	mOutputControls.mLED1 = led1;
199	mOutputControls.mLED2 = led2;	
200	mOutputControls.mLED3 = led3;
201	mOutputControls.mLED4 = led4;
202	return UpdateOutput();
203}
204
205bool cWiiMote::UpdateOutput()
206{
207	ClearBuffer();
208	mOutputBuffer[0] = OUTPUT_CHANNEL_LED;
209	mOutputBuffer[1] =  (mOutputControls.mVibration ? 0x1 : 0x0) |
210						(mOutputControls.mLED1 ? 0x1 : 0x0) << 4 | 
211						(mOutputControls.mLED2 ? 0x1 : 0x0) << 5 | 
212						(mOutputControls.mLED3 ? 0x1 : 0x0) << 6 | 
213						(mOutputControls.mLED4 ? 0x1 : 0x0) << 7; 
214	return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
215}
216
217bool cWiiMote::HeartBeat(int timeout)
218{
219	bool retval = true;
220	int bytes_read = 0;
221	
222
223	//most of these reports aren't implemented yet. I don't have a sensor bar or a nunchuck :)
224	if (mHIDDevice.ReadFromDevice(mInputBuffer,mInputBufferSize,bytes_read) && (bytes_read > 0,timeout))
225	{
226		const int channel = mInputBuffer[0];
227		switch (channel)
228		{
229			case INPUT_CHANNEL_EXPANSION_PORT:// 	 6 	Expansion Port change
230				{
231					ParseButtonReport(&mInputBuffer[1]);
232					ParseExpansionReport(&mInputBuffer[2]);
233					bool restart = mDataStreamRunning;
234					StopDataStream();
235					InitNunchuck();
236					
237					if (restart)
238					{
239						retval = StartDataStream();
240					}
241				}
242			break;
243
244			case INPUT_CHANNEL_BUTTONS_ONLY:// 	2 	Buttons only
245				ParseButtonReport(&mInputBuffer[1]);
246			break;
247
248			case 0x21:// 	21 	Read data
249				ParseButtonReport(&mInputBuffer[1]);
250				ParseReadData(&mInputBuffer[3]);
251				break;
252
253			case INPUT_CHANNEL_WRITE_CONFIRM:// 	4 	Write data
254			break;
255
256			case 0x31:// 	5 	Buttons | Motion Sensing Report
257				ParseButtonReport(&mInputBuffer[1]);
258				ParseMotionReport(&mInputBuffer[3]);
259			break;
260
261			case 0x32:// 	16 	Buttons | Expansion Port | IR??
262				ParseButtonReport(&mInputBuffer[1]);
263			break;
264
265			case INPUT_CHANNEL_MOTION_IR:
266				ParseButtonReport(&mInputBuffer[1]);
267				ParseMotionReport(&mInputBuffer[3]);
268				ParseIRReport(&mInputBuffer[6]);
269			break;
270
271			case INPUT_CHANNEL_MOTION_CHUCK_IR:
272				ParseButtonReport(&mInputBuffer[1]);
273				ParseMotionReport(&mInputBuffer[3]);
274				ParseIRReport(&mInputBuffer[6]);
275				ParseChuckReport(&mInputBuffer[16]);
276			break;
277
278			case INPUT_CHANNEL_MOTION_CHUCK:
279				ParseButtonReport(&mInputBuffer[1]);
280				ParseMotionReport(&mInputBuffer[3]);
281				ParseChuckReport(&mInputBuffer[6]);
282
283			break;
284
285			case 0x34:// 	21 	Buttons | Expansion Port | IR??
286			case 0x3d:// 	21 	Buttons | Expansion Port | IR??
287				ParseButtonReport(&mInputBuffer[1]);
288			break;
289
290			case 0x3e:// 	21 	Buttons | Motion Sensing Report | IR??
291			case 0x3f:// 	21 	Buttons | Motion Sensing Report | IR??
292				ParseButtonReport(&mInputBuffer[1]);
293			break;
294			default:
295				retval = false;
296				//unknown report
297			break;
298		}		
299	}
300	return retval;
301}
302
303void cWiiMote::ParseExpansionReport(const unsigned char *data)
304{
305	//four bytes long
306	mLastExpansionReport.mAttachmentPluggedIn = (data[0] & 0x02) != 0;
307	mLastExpansionReport.mIREnabled = (data[0] & 0x08) != 0;
308	mLastExpansionReport.mSpeakerEnabled = (data[0] & 0x04) != 0;
309	mLastExpansionReport.mLED1On = (data[0] & 0x10) != 0;
310	mLastExpansionReport.mLED2On = (data[0] & 0x20) != 0;
311	mLastExpansionReport.mLED3On = (data[0] & 0x40) != 0;
312	mLastExpansionReport.mLED4On = (data[0] & 0x80) != 0;
313	
314	//two unknown bytes
315	mLastExpansionReport.mBatteryLevel = data[3];
316}
317
318void cWiiMote::ParseButtonReport(const unsigned char * data)
319{
320	//two bytes long
321	mLastButtonStatus.mA = (data[1] & 0x08) != 0;
322 	mLastButtonStatus.mB = (data[1] & 0x04) != 0;
323 	mLastButtonStatus.m1 = (data[1] & 0x02) != 0;
324 	mLastButtonStatus.m2 = (data[1] & 0x01) != 0;
325 	mLastButtonStatus.mPlus = (data[0] & 0x10) != 0;
326 	mLastButtonStatus.mMinus = (data[1] & 0x10) != 0;
327 	mLastButtonStatus.mHome = (data[1] & 0x80) != 0;
328 	mLastButtonStatus.mUp = (data[0] & 0x08) != 0;
329 	mLastButtonStatus.mDown = (data[0] & 0x04) != 0;
330 	mLastButtonStatus.mLeft = (data[0] & 0x01) != 0;
331 	mLastButtonStatus.mRight = (data[0] & 0x02) != 0;
332}
333
334void cWiiMote::ParseMotionReport(const unsigned char * data)
335{
336	//three bytes long
337	mLastMotionReport.mX = data[0];
338	mLastMotionReport.mY = data[1];
339	mLastMotionReport.mZ = data[2];
340}
341
342void cWiiMote::PrintStatus() const
343{
344	float wX,wY,wZ;
345	float cX,cY,cZ;
346	float sX,sY;
347	float irX,irY;
348	
349	wX =wY=wZ=cX=cY=cZ=sX=sY=irX=irY=0.f;
350
351	GetCalibratedAcceleration(wX,wY,wZ);
352	printf("W:[%+1.2f %+1.2f %+1.2f] ",wX,wY,wZ);
353
354	if (mNunchuckAttached)
355	{
356		GetCalibratedChuckAcceleration(cX,cY,cZ);
357		printf("N:[%+1.2f %+1.2f %+1.2f] ",cX,cY,cZ);
358
359		GetCalibratedChuckStick(sX,sY);
360		printf("S:[%+1.2f %+1.2f] ",sX,sY);
361	}
362
363	if (mIRRunning)
364	{
365		if (GetIRP1(irX,irY))
366		{
367			printf("P1:[%+1.2f %+1.2f]",irX,irY);
368		}
369		if (GetIRP2(irX,irY))
370		{
371			printf("P2:[%+1.2f %+1.2f]",irX,irY);
372		}
373	}
374
375
376	//print the button status
377	if (mLastButtonStatus.m1)
378		printf("1");
379	if (mLastButtonStatus.m2)
380		printf("2");
381	if (mLastButtonStatus.mA)
382		printf("A");
383	if (mLastButtonStatus.mB)
384		printf("B");
385	if (mLastButtonStatus.mPlus)
386		printf("+");
387	if (mLastButtonStatus.mMinus)
388		printf("-");
389	if (mLastButtonStatus.mUp)
390		printf("U");
391	if (mLastButtonStatus.mDown)
392		printf("D");
393	if (mLastButtonStatus.mLeft)
394		printf("L");
395	if (mLastButtonStatus.mRight)
396		printf("R");
397	if (mLastButtonStatus.mHome)
398		printf("H");
399
400	if (mNunchuckAttached)
401	{
402		if (mLastChuckReport.mButtonZ)
403			printf("Z");
404		if (mLastChuckReport.mButtonC)
405			printf("C");
406	}
407
408	printf("\n");
409
410}
411
412
413bool cWiiMote::SelectInputChannel(bool continuous, unsigned char channel)
414{
415	ClearBuffer();
416	mOutputBuffer[0] = OUTPUT_CHANNEL_REPORT;
417	mOutputBuffer[1] = (continuous ? REQUEST_CONTINUOUS_REPORTS : REQUEST_SINGLE_REPORTS) | (mOutputControls.mVibration ? 0x1 : 0x0);
418	mOutputBuffer[2] = channel;
419	return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
420}
421
422
423//this may or may not work to read buffers greater than 16 bytes. . . .
424bool cWiiMote::IssueReadRequest(unsigned int address, unsigned short size, unsigned char * buffer)
425{
426	bool retval = false;
427	if (mReadInfo.mReadStatus != tMemReadInfo::READ_PENDING)
428	{
429		ClearBuffer();
430		mOutputBuffer[0] = OUTPUT_READ_MEMORY;
431		mOutputBuffer[1] = (((address & 0xff000000) >> 24) & 0xFE) | (mOutputControls.mVibration ? 0x1 : 0x0);
432		mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
433		mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
434		mOutputBuffer[4] = (address & 0xff);
435		
436		mOutputBuffer[5] = (size & 0xff00) >> 8;
437		mOutputBuffer[6] = (size & 0xff);
438		
439		if (mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize))
440		{
441			mReadInfo.mReadStatus = tMemReadInfo::READ_PENDING;
442			mReadInfo.mReadBuffer = buffer;
443			mReadInfo.mTotalBytesToRead = size;
444			mReadInfo.mBytesRead =0;
445			mReadInfo.mBaseAddress = (unsigned short)(address & 0xFFFF);
446			retval = true;
447		}
448	}
449
450	return retval;
451}
452
453void cWiiMote::ParseReadData(const unsigned char * data)
454{
455	if(mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
456	{
457		const bool error = (data[0] & 0x0F) != 0;
458		if (error)
459		{
460			mReadInfo.mReadStatus = tMemReadInfo::READ_ERROR;
461		}
462		else
463		{
464			unsigned char bytes = (data[0] >> 4)+1;
465			unsigned short offset = ((unsigned short)data[1] << 8) + data[2];
466			unsigned int space_left_in_buffer = mReadInfo.mTotalBytesToRead -  mReadInfo.mBytesRead;
467			if (offset == mReadInfo.mBytesRead + mReadInfo.mBaseAddress &&
468				space_left_in_buffer >= bytes)
469			{
470				memcpy(&mReadInfo.mReadBuffer[mReadInfo.mBytesRead],&data[3],bytes);
471				
472				mReadInfo.mBytesRead+= bytes;
473				if (mReadInfo.mBytesRead >= mReadInfo.mTotalBytesToRead)
474				{
475					mReadInfo.mReadStatus = tMemReadInfo::READ_COMPLETE;
476				}
477			}
478		}
479	}
480
481}
482
483bool cWiiMote::ReadData(unsigned int address, unsigned short size, unsigned char * buffer)
484{
485	if (IssueReadRequest(address, size,buffer))
486	{
487		while (mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
488		{
489			if (!HeartBeat(1000))
490			{
491				break;
492			}
493		}
494	}
495	return mReadInfo.mReadStatus == tMemReadInfo::READ_COMPLETE;
496}
497
498bool cWiiMote::ReadCalibrationData()
499{
500	bool retval = false;
501	unsigned char buffer[CALIBRATION_DATA_LENGTH];
502	if (ReadData(CALIBRATION_ADDRESS, CALIBRATION_DATA_LENGTH,buffer))
503	{
504		mAccelCalibrationData.mXZero = buffer[0];
505		mAccelCalibrationData.mYZero = buffer[1];
506		mAccelCalibrationData.mZZero = buffer[2];
507		mAccelCalibrationData.mXG = buffer[4];
508		mAccelCalibrationData.mYG = buffer[5];
509		mAccelCalibrationData.mZG = buffer[6];
510		retval = true;
511	}
512	
513	return retval;
514}
515
516void cWiiMote::GetCalibratedAcceleration(float & x, float & y, float &z) const
517{
518 	x = (mLastMotionReport.mX - mAccelCalibrationData.mXZero) / (float)(mAccelCalibrationData.mXG- mAccelCalibrationData.mXZero);
519	y = (mLastMotionReport.mY - mAccelCalibrationData.mYZero) / (float)(mAccelCalibrationData.mYG- mAccelCalibrationData.mYZero);
520	z = (mLastMotionReport.mZ - mAccelCalibrationData.mZZero) / (float)(mAccelCalibrationData.mZG- mAccelCalibrationData.mZZero);
521}
522
523void cWiiMote::GetCalibratedChuckAcceleration(float & x, float & y, float &z) const
524{
525	if (!mNunchuckAttached)
526	{
527		x = y = z = 0.f;
528		return;
529	}
530
531	x = (mLastChuckReport.mAccelX - mNunchuckAccelCalibrationData.mXZero) / (float)(mNunchuckAccelCalibrationData.mXG- mNunchuckAccelCalibrationData.mXZero);
532	y = (mLastChuckReport.mAccelY - mNunchuckAccelCalibrationData.mYZero) / (float)(mNunchuckAccelCalibrationData.mYG- mNunchuckAccelCalibrationData.mYZero);
533	z = (mLastChuckReport.mAccelZ - mNunchuckAccelCalibrationData.mZZero) / (float)(mNunchuckAccelCalibrationData.mZG- mNunchuckAccelCalibrationData.mZZero);
534}
535void cWiiMote::GetCalibratedChuckStick(float & x, float & y) const
536{
537	if (!mNunchuckAttached)
538	{
539		x = y = 0.f;
540		return;
541	}
542
543	if (mLastChuckReport.mStickX < mNunchuckStickCalibrationData.mXmid)
544	{
545		x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmin) / (float)(mNunchuckStickCalibrationData.mXmid - mNunchuckStickCalibrationData.mXmin)) -  1.f;
546	}
547	else
548	{
549		x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmid) / (float)(mNunchuckStickCalibrationData.mXmax - mNunchuckStickCalibrationData.mXmid));
550	}
551
552	if (mLastChuckReport.mStickY < mNunchuckStickCalibrationData.mYmid)
553	{
554		y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmin) / (float)(mNunchuckStickCalibrationData.mYmid - mNunchuckStickCalibrationData.mYmin)) -  1.f;
555	}
556	else
557	{
558		y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmid) / (float)(mNunchuckStickCalibrationData.mYmax - mNunchuckStickCalibrationData.mYmid));
559	}
560}
561
562
563bool cWiiMote::WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer)
564{
565	bool retval = false;
566	if (size <= 16)
567	{
568		ClearBuffer();
569		mOutputBuffer[0] = OUTPUT_WRITE_MEMORY;
570		mOutputBuffer[1] = (address & 0xff000000) >> 24 | (mOutputControls.mVibration ? 0x1 : 0x0);
571		mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
572		mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
573		mOutputBuffer[4] = (address & 0xff);
574		mOutputBuffer[5] = size;
575		memcpy(&mOutputBuffer[6],buffer,size);
576		retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
577	}
578
579	return retval;
580}
581
582bool cWiiMote::InitNunchuck()
583{
584
585	bool retval = false;
586	
587	//first init the nunchuck, if it is present
588	if (WriteMemory(NUNCHUCK_INIT_ADDRESS,1,&NUNCHUCK_INIT_VAL))
589	{
590	
591		unsigned char buffer[16];
592		//now try to read the nunchuck's calibration data
593		if (ReadData(NUNCHUCK_CALIBRATION_ADDRESS,16,buffer))
594		{
595			
596			//note that this hasn't worked properly for me yet (I get all 0xff). 
597			/*mNunchuckAccelCalibrationData.mXZero = NunChuckByte(buffer[0]);
598			mNunchuckAccelCalibrationData.mYZero = NunChuckByte(buffer[1]);
599			mNunchuckAccelCalibrationData.mZZero = NunChuckByte(buffer[2]);
600
601			mNunchuckAccelCalibrationData.mXG = NunChuckByte(buffer[4]);
602			mNunchuckAccelCalibrationData.mYG = NunChuckByte(buffer[5]);
603			mNunchuckAccelCalibrationData.mZG = NunChuckByte(buffer[6]);
604
605			mNunchuckStickCalibrationData.mXmax = NunChuckByte(buffer[8]);
606			mNunchuckStickCalibrationData.mXmin = NunChuckByte(buffer[9]);
607			mNunchuckStickCalibrationData.mXmid = NunChuckByte(buffer[10]);
608			mNunchuckStickCalibrationData.mYmax = NunChuckByte(buffer[11]);
609			mNunchuckStickCalibrationData.mYmin = NunChuckByte(buffer[12]);
610			mNunchuckStickCalibrationData.mYmid = NunChuckByte(buffer[13]);*/
611
612			//these are default values from the wiili wiki
613			mNunchuckAccelCalibrationData.mXZero = 0x7E;
614			mNunchuckAccelCalibrationData.mYZero = 0x7A;
615			mNunchuckAccelCalibrationData.mZZero = 0x7D;
616			mNunchuckAccelCalibrationData.mXG = 0xB0;
617			mNunchuckAccelCalibrationData.mYG = 0xAF;
618			mNunchuckAccelCalibrationData.mZG = 0xB1;
619			mNunchuckStickCalibrationData.mXmax = 0xe5;
620			mNunchuckStickCalibrationData.mXmin = 0x21;
621			mNunchuckStickCalibrationData.mXmid =  0x7c;
622			mNunchuckStickCalibrationData.mYmax = 0xe7;
623			mNunchuckStickCalibrationData.mYmin =  0x23;
624			mNunchuckStickCalibrationData.mYmid = 0x7a;
625			retval = true;
626
627		}
628	}
629	mNunchuckAttached = retval;
630	return retval;
631}
632
633void cWiiMote::ParseChuckReport(const unsigned char * data)
634{
635	mLastChuckReport.mStickX = NunChuckByte(data[0]);
636	mLastChuckReport.mStickY = NunChuckByte(data[1]);
637	mLastChuckReport.mAccelX = NunChuckByte(data[2]);
638	mLastChuckReport.mAccelY = NunChuckByte(data[3]);
639	mLastChuckReport.mAccelZ = NunChuckByte(data[4]);
640	mLastChuckReport.mButtonC = (NunChuckByte(data[5]) & 0x2) == 0;
641	mLastChuckReport.mButtonZ = (NunChuckByte(data[5]) & 0x1) == 0;
642}
643
644bool cWiiMote::EnableIR()
645{
646	bool retval = false;
647	
648	DisableIR();
649
650	if (!mIRRunning)
651	{
652		ClearBuffer();
653		mOutputBuffer[0] = OUTPUT_ENABLE_IR;
654		mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
655		retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
656		
657		if (retval)
658		{
659			mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
660			mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
661			retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
662		}
663
664		if (retval)
665		{
666			unsigned char val = 0x1;
667			retval = WriteMemory(IR_REG_1,1,&val);
668		}
669		
670		if (retval)
671		{
672			retval = WriteMemory(IR_SENS_ADDR_1,9,IR_SENS_MIDRANGE_PART1);
673		}
674
675		if (retval)
676		{
677			retval = WriteMemory(IR_SENS_ADDR_2,2,IR_SENS_MIDRANGE_PART2);
678		}
679
680
681		if (retval)
682		{
683			retval = WriteMemory(IR_REG_2,1,&IR_MODE_EXP);
684		}
685		
686		if (retval)
687		{
688			unsigned char val = 0x8;
689			retval = WriteMemory(IR_REG_1,1,&val);
690		}
691
692
693		mIRRunning = retval;
694	}
695	return retval;
696
697}
698
699bool cWiiMote::DisableIR()
700{
701	bool retval = false;
702
703	if (mIRRunning)
704	{
705		ClearBuffer();
706		mOutputBuffer[0] = OUTPUT_ENABLE_IR;
707		mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
708		retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
709		
710		if (retval)
711		{
712			mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
713			mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
714			retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
715		}
716
717		mIRRunning = false;
718	}
719	return retval;
720
721}
722
723void cWiiMote::ParseIRReport(const unsigned char * data)
724{
725	mLastIRReport.mP1X = data[0] << 2 | (data[2] & 0x30) >>4;
726	mLastIRReport.mP1Y = data[1] << 2 | (data[2] & 0xc0) >>6;
727	mLastIRReport.mP1Size = data[2] & 0xf;
728
729	mLastIRReport.mP2X = data[3] << 2 | (data[5] & 0x30) >>4;
730	mLastIRReport.mP2Y = data[4] << 2 | (data[5] & 0xc0) >>6;
731	mLastIRReport.mP2Size = data[5] & 0xf;
732
733	mLastIRReport.mP1Found =  !(data[0] == 0xff && data[1] == 0xff && data[2] == 0xff);
734	mLastIRReport.mP2Found =  !(data[3] == 0xff && data[4] == 0xff && data[5] == 0xff);
735}
736
737bool cWiiMote::GetIRP1(float &x, float &y) const
738{
739	bool retval = false;
740	if (mIRRunning && mLastIRReport.mP1Found)
741	{
742		x = mLastIRReport.mP1X / 1024.f;
743		y = mLastIRReport.mP1Y / 1024.f;
744		retval = true;
745	}
746	return retval;
747}
748
749
750bool cWiiMote::GetIRP2(float &x, float &y) const
751{
752	bool retval = false;
753	if (mIRRunning && mLastIRReport.mP2Found)
754	{
755		x = mLastIRReport.mP2X / 1024.f;
756		y = mLastIRReport.mP2Y / 1024.f;
757		retval = true;
758	}
759	return retval;
760
761}
762
763bool cWiiMote::StartDataStream()
764{
765	bool retval = false;
766	
767	StopDataStream();
768
769	if (mNunchuckAttached)
770	{
771		retval =SetReportMode(REPORT_MODE_MOTION_CHUCK_IR);
772	}
773	else
774	{
775		retval = SetReportMode(REPORT_MODE_MOTION_IR);
776	}
777	EnableIR();
778
779	mDataStreamRunning = retval;
780	return retval;
781}
782
783
784bool cWiiMote::StopDataStream()
785{
786	if (mDataStreamRunning)
787	{
788		mDataStreamRunning = false;
789		DisableIR();
790		SetReportMode(REPORT_MODE_EVENT_BUTTONS);
791	}
792	return true;;
793}
794#endif