Home | History | Annotate | Download | only in WiiMote
      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 
     68 cWiiMote::cWiiMote()
     69 {
     70 	Init();
     71 }
     72 
     73 cWiiMote::~cWiiMote()
     74 {
     75 	Disconnect();
     76 }
     77 
     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 
     95 bool cWiiMote::SetReportMode(eReportMode mode)
     96 {
     97 	mReportMode = mode;
     98 	return SendReportMode();
     99 }
    100 
    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 
    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 
    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 
    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 
    181 void cWiiMote::ClearBuffer()
    182 {
    183 	memset(mOutputBuffer,0, mOutputBufferSize);
    184 }
    185 
    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 
    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 
    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 
    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 
    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 
    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 
    342 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 
    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. . . .
    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 
    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 
    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 
    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 
    516 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 
    523 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 }
    535 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 
    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 
    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 
    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 
    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 
    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 
    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 
    737 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 
    750 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 
    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 
    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