• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
15 const unsigned char OUTPUT_CHANNEL_FORCE_FEEDBACK = 0x13;
16 const unsigned char OUTPUT_CHANNEL_LED = 0x11;
17 const unsigned char OUTPUT_CHANNEL_REPORT = 0x12;
18 const unsigned char OUTPUT_READ_MEMORY = 0x17;
19 const unsigned char OUTPUT_WRITE_MEMORY = 0x16;
20 
21 const unsigned char OUTPUT_ENABLE_IR = 0x13;
22 const unsigned char OUTPUT_ENABLE_IR2 = 0x1a;
23 
24 //report request types
25 const unsigned char REQUEST_CONTINUOUS_REPORTS = 0x4;
26 const unsigned char REQUEST_SINGLE_REPORTS = 0x0;
27 
28 //input channels
29 const unsigned char INPUT_CHANNEL_BUTTONS_ONLY = 0x30;
30 const unsigned char INPUT_CHANNEL_BUTTONS_MOTION = 0x31;
31 const unsigned char INPUT_CHANNEL_WRITE_CONFIRM = 0x22;
32 const unsigned char INPUT_CHANNEL_EXPANSION_PORT = 0x20;
33 
34 const unsigned char INPUT_CHANNEL_MOTION_IR = 0x33;
35 const unsigned char INPUT_CHANNEL_MOTION_CHUCK_IR = 0x37;
36 const unsigned char INPUT_CHANNEL_MOTION_CHUCK = 0x35;
37 
38 //the ID values for a wiimote
39 const unsigned short mVendorID = 0x057E;
40 const unsigned short mDeviceID = 0x0306;
41 
42 //how to find the calibration data for the wiimote
43 const unsigned short CALIBRATION_ADDRESS = 0x16;
44 const unsigned short CALIBRATION_DATA_LENGTH = 7;
45 
46 //nunchuck constants
47 const unsigned long NUNCHUCK_STATUS_ADDRESS = 0x04A40000;
48 const unsigned long NUNCHUCK_CALIBRATION_ADDRESS = 0x04A40020;
49 const unsigned long NUNCHUCK_CALIBRATION_ADDRESS_2 = 0x04A40030;
50 const unsigned long NUNCHUCK_INIT_ADDRESS= 0x04A40040;
51 const unsigned long NUNCHUK_ID_ADDRESS = 0x04a400f0;
52 const unsigned char NUNCHUCK_INIT_VAL= 0x0;
53 
54 //IR constants
55 const unsigned long IR_REG_1 = 0x04b00030;
56 const unsigned long IR_REG_2 = 0x04b00033;
57 const unsigned long IR_SENS_ADDR_1 = 0x04b00000;
58 const unsigned long IR_SENS_ADDR_2 = 0x04b0001a;
59 
60 const unsigned char IR_SENS_MIDRANGE_PART1[] = {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64};
61 const unsigned char IR_SENS_MIDRANGE_PART2[] = {0x63, 0x03};
62 
63 const unsigned char IR_MODE_OFF = 0;
64 const unsigned char IR_MODE_STD = 1;
65 const unsigned char IR_MODE_EXP = 3;
66 const unsigned char IR_MODE_FULL = 5;
67 
cWiiMote()68 cWiiMote::cWiiMote()
69 {
70 	Init();
71 }
72 
~cWiiMote()73 cWiiMote::~cWiiMote()
74 {
75 	Disconnect();
76 }
77 
Init()78 void 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 
SetReportMode(eReportMode mode)95 bool cWiiMote::SetReportMode(eReportMode mode)
96 {
97 	mReportMode = mode;
98 	return SendReportMode();
99 }
100 
SendReportMode()101 bool 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 
ConnectToDevice(int index)142 bool 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 
Disconnect()157 bool 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 
SetVibration(bool vib_on)170 bool 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 
ClearBuffer()181 void cWiiMote::ClearBuffer()
182 {
183 	memset(mOutputBuffer,0, mOutputBufferSize);
184 }
185 
SetLEDs(bool led1,bool led2,bool led3,bool led4)186 bool 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 
UpdateOutput()205 bool 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 
HeartBeat(int timeout)217 bool 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 
ParseExpansionReport(const unsigned char * data)303 void 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 
ParseButtonReport(const unsigned char * data)318 void 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 
ParseMotionReport(const unsigned char * data)334 void 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 
PrintStatus() const342 void 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 
SelectInputChannel(bool continuous,unsigned char channel)413 bool 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. . . .
IssueReadRequest(unsigned int address,unsigned short size,unsigned char * buffer)424 bool 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 
ParseReadData(const unsigned char * data)453 void 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 
ReadData(unsigned int address,unsigned short size,unsigned char * buffer)483 bool 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 
ReadCalibrationData()498 bool 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 
GetCalibratedAcceleration(float & x,float & y,float & z) const516 void 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 
GetCalibratedChuckAcceleration(float & x,float & y,float & z) const523 void 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 }
GetCalibratedChuckStick(float & x,float & y) const535 void 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 
WriteMemory(unsigned int address,unsigned char size,const unsigned char * buffer)563 bool 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 
InitNunchuck()582 bool 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 
ParseChuckReport(const unsigned char * data)633 void 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 
EnableIR()644 bool 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 
DisableIR()699 bool 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 
ParseIRReport(const unsigned char * data)723 void 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 
GetIRP1(float & x,float & y) const737 bool 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 
GetIRP2(float & x,float & y) const750 bool 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 
StartDataStream()763 bool 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 
StopDataStream()784 bool 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
795