text: #include "OISConfig.h"
  #ifdef OIS_WIN32_WIIMOTE_SUPPORT
  //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
  //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.
  
  //Edited for Toshiba Stack support (hopefully also all others) by
  //Sean Stellingwerff (http://sean.stellingwerff.com) using information
  //gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D)
  
  //#include "stdafx.h"
  #include "wiimote.h"
  #include <stdio.h>
  
  //output channels
  const unsigned char OUTPUT_CHANNEL_FORCE_FEEDBACK = 0x13;
  const unsigned char OUTPUT_CHANNEL_LED			  = 0x11;
  const unsigned char OUTPUT_CHANNEL_REPORT		  = 0x12;
  const unsigned char OUTPUT_READ_MEMORY			  = 0x17;
  const unsigned char OUTPUT_WRITE_MEMORY			  = 0x16;
  
  const unsigned char OUTPUT_ENABLE_IR  = 0x13;
  const unsigned char OUTPUT_ENABLE_IR2 = 0x1a;
  
  //report request types
  const unsigned char REQUEST_CONTINUOUS_REPORTS = 0x4;
  const unsigned char REQUEST_SINGLE_REPORTS	 = 0x0;
  
  //input channels
  const unsigned char INPUT_CHANNEL_BUTTONS_ONLY   = 0x30;
  const unsigned char INPUT_CHANNEL_BUTTONS_MOTION = 0x31;
  const unsigned char INPUT_CHANNEL_WRITE_CONFIRM  = 0x22;
  const unsigned char INPUT_CHANNEL_EXPANSION_PORT = 0x20;
  
  const unsigned char INPUT_CHANNEL_MOTION_IR		  = 0x33;
  const unsigned char INPUT_CHANNEL_MOTION_CHUCK_IR = 0x37;
  const unsigned char INPUT_CHANNEL_MOTION_CHUCK	= 0x35;
  
  //the ID values for a wiimote
  const unsigned short mVendorID = 0x057E;
  const unsigned short mDeviceID = 0x0306;
  
  //how to find the calibration data for the wiimote
  const unsigned short CALIBRATION_ADDRESS	 = 0x16;
  const unsigned short CALIBRATION_DATA_LENGTH = 7;
  
  //nunchuck constants
  const unsigned long NUNCHUCK_STATUS_ADDRESS		   = 0x04A40000;
  const unsigned long NUNCHUCK_CALIBRATION_ADDRESS   = 0x04A40020;
  const unsigned long NUNCHUCK_CALIBRATION_ADDRESS_2 = 0x04A40030;
  const unsigned long NUNCHUCK_INIT_ADDRESS		   = 0x04A40040;
  const unsigned long NUNCHUK_ID_ADDRESS			   = 0x04a400f0;
  const unsigned char NUNCHUCK_INIT_VAL			   = 0x0;
  
  //IR constants
  const unsigned long IR_REG_1	   = 0x04b00030;
  const unsigned long IR_REG_2	   = 0x04b00033;
  const unsigned long IR_SENS_ADDR_1 = 0x04b00000;
  const unsigned long IR_SENS_ADDR_2 = 0x04b0001a;
  
  const unsigned char IR_SENS_MIDRANGE_PART1[] = { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64 };
  const unsigned char IR_SENS_MIDRANGE_PART2[] = { 0x63, 0x03 };
  
  const unsigned char IR_MODE_OFF  = 0;
  const unsigned char IR_MODE_STD  = 1;
  const unsigned char IR_MODE_EXP  = 3;
  const unsigned char IR_MODE_FULL = 5;
  
  cWiiMote::cWiiMote()
  {
  	Init();
  }
  
  cWiiMote::~cWiiMote()
  {
  	Disconnect();
  }
  
  void cWiiMote::Init()
  {
  	mReportMode = REPORT_MODE_EVENT_BUTTONS;
  	mLastButtonStatus.Init();
  	mLastExpansionReport.Init();
  	mLastMotionReport.Init();
  	mOutputControls.Init();
  	mReadInfo.Init();
  	mAccelCalibrationData.Init();
  	mNunchuckAccelCalibrationData.Init();
  	mNunchuckStickCalibrationData.Init();
  	mLastIRReport.Init();
  	mNunchuckAttached  = false;
  	mIRRunning		   = false;
  	mDataStreamRunning = false;
  }
  
  bool cWiiMote::SetReportMode(eReportMode mode)
  {
  	mReportMode = mode;
  	return SendReportMode();
  }
  
  bool cWiiMote::SendReportMode()
  {
  	bool continuous		  = true;
  	unsigned char channel = INPUT_CHANNEL_BUTTONS_ONLY;
  	bool check_chuck	  = false;
  
  	switch(mReportMode)
  	{
  		case REPORT_MODE_MOTION_IR:
  			channel = INPUT_CHANNEL_MOTION_IR;
  			break;
  		case REPORT_MODE_MOTION_CHUCK_IR:
  			channel		= INPUT_CHANNEL_MOTION_CHUCK_IR;
  			check_chuck = true;
  			break;
  		case REPORT_MODE_MOTION_CHUCK:
  			channel		= INPUT_CHANNEL_MOTION_CHUCK;
  			check_chuck = true;
  			break;
  		case REPORT_MODE_MOTION:
  			channel = INPUT_CHANNEL_BUTTONS_MOTION;
  			break;
  		case REPORT_MODE_EVENT_BUTTONS:
  			channel	= INPUT_CHANNEL_BUTTONS_ONLY;
  			continuous = false;
  			break;
  		default:
  			break;
  	}
  
  	//check to make sure that there is a chuck attached
  	//	if (check_chuck && !mNunchuckAttached)
  	//	{
  	//		printf("Supposed to check for nunchuck, but couldn't find one!");
  	//		return false;
  	//	}
  
  	bool retval = SelectInputChannel(continuous, channel);
  	return retval;
  }
  
  bool cWiiMote::ConnectToDevice(int index)
  {
  	Init();
  	const bool retval = mHIDDevice.Connect(mDeviceID, mVendorID, index) && SetReportMode(REPORT_MODE_MOTION_CHUCK_IR) && UpdateOutput() && ReadCalibrationData();
  
  	if(retval)
  	{
  		InitNunchuck();
  	}
  	return retval;
  }
  
  bool cWiiMote::Disconnect()
  {
  	bool retval = false;
  	StopDataStream();
  
  	if(mHIDDevice.IsConnected())
  	{
  		retval = mHIDDevice.Disconnect();
  	}
  
  	return retval;
  }
  
  bool cWiiMote::SetVibration(bool vib_on)
  {
  	bool retval = true;
  	if(mOutputControls.mVibration != vib_on)
  	{
  		mOutputControls.mVibration = vib_on;
  		retval					   = UpdateOutput();
  	}
  	return retval;
  }
  
  void cWiiMote::ClearBuffer()
  {
  	memset(mOutputBuffer, 0, mOutputBufferSize);
  }
  
  bool cWiiMote::SetLEDs(bool led1, bool led2, bool led3, bool led4)
  {
  	const bool no_change = mOutputControls.mLED1 == led1 && mOutputControls.mLED2 == led2 && mOutputControls.mLED3 == led3 && mOutputControls.mLED4 == led4;
  
  	if(no_change)
  	{
  		return true;
  	}
  
  	mOutputControls.mLED1 = led1;
  	mOutputControls.mLED2 = led2;
  	mOutputControls.mLED3 = led3;
  	mOutputControls.mLED4 = led4;
  	return UpdateOutput();
  }
  
  bool cWiiMote::UpdateOutput()
  {
  	ClearBuffer();
  	mOutputBuffer[0] = OUTPUT_CHANNEL_LED;
  	mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0) | (mOutputControls.mLED1 ? 0x1 : 0x0) << 4 | (mOutputControls.mLED2 ? 0x1 : 0x0) << 5 | (mOutputControls.mLED3 ? 0x1 : 0x0) << 6 | (mOutputControls.mLED4 ? 0x1 : 0x0) << 7;
  	return mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize);
  }
  
  bool cWiiMote::HeartBeat(int timeout)
  {
  	bool retval	= true;
  	int bytes_read = 0;
  
  	//most of these reports aren't implemented yet. I don't have a sensor bar or a nunchuck :)
  	if(mHIDDevice.ReadFromDevice(mInputBuffer, mInputBufferSize, bytes_read) && (bytes_read > 0, timeout))
  	{
  		const int channel = mInputBuffer[0];
  		switch(channel)
  		{
  			case INPUT_CHANNEL_EXPANSION_PORT: // 	 6 	Expansion Port change
  			{
  				ParseButtonReport(&mInputBuffer[1]);
  				ParseExpansionReport(&mInputBuffer[2]);
  				bool restart = mDataStreamRunning;
  				StopDataStream();
  				InitNunchuck();
  
  				if(restart)
  				{
  					retval = StartDataStream();
  				}
  			}
  			break;
  
  			case INPUT_CHANNEL_BUTTONS_ONLY: // 	2 	Buttons only
  				ParseButtonReport(&mInputBuffer[1]);
  				break;
  
  			case 0x21: // 	21 	Read data
  				ParseButtonReport(&mInputBuffer[1]);
  				ParseReadData(&mInputBuffer[3]);
  				break;
  
  			case INPUT_CHANNEL_WRITE_CONFIRM: // 	4 	Write data
  				break;
  
  			case 0x31: // 	5 	Buttons | Motion Sensing Report
  				ParseButtonReport(&mInputBuffer[1]);
  				ParseMotionReport(&mInputBuffer[3]);
  				break;
  
  			case 0x32: // 	16 	Buttons | Expansion Port | IR??
  				ParseButtonReport(&mInputBuffer[1]);
  				break;
  
  			case INPUT_CHANNEL_MOTION_IR:
  				ParseButtonReport(&mInputBuffer[1]);
  				ParseMotionReport(&mInputBuffer[3]);
  				ParseIRReport(&mInputBuffer[6]);
  				break;
  
  			case INPUT_CHANNEL_MOTION_CHUCK_IR:
  				ParseButtonReport(&mInputBuffer[1]);
  				ParseMotionReport(&mInputBuffer[3]);
  				ParseIRReport(&mInputBuffer[6]);
  				ParseChuckReport(&mInputBuffer[16]);
  				break;
  
  			case INPUT_CHANNEL_MOTION_CHUCK:
  				ParseButtonReport(&mInputBuffer[1]);
  				ParseMotionReport(&mInputBuffer[3]);
  				ParseChuckReport(&mInputBuffer[6]);
  
  				break;
  
  			case 0x34: // 	21 	Buttons | Expansion Port | IR??
  			case 0x3d: // 	21 	Buttons | Expansion Port | IR??
  				ParseButtonReport(&mInputBuffer[1]);
  				break;
  
  			case 0x3e: // 	21 	Buttons | Motion Sensing Report | IR??
  			case 0x3f: // 	21 	Buttons | Motion Sensing Report | IR??
  				ParseButtonReport(&mInputBuffer[1]);
  				break;
  			default:
  				retval = false;
  				//unknown report
  				break;
  		}
  	}
  	return retval;
  }
  
  void cWiiMote::ParseExpansionReport(const unsigned char* data)
  {
  	//four bytes long
  	mLastExpansionReport.mAttachmentPluggedIn = (data[0] & 0x02) != 0;
  	mLastExpansionReport.mIREnabled			  = (data[0] & 0x08) != 0;
  	mLastExpansionReport.mSpeakerEnabled	  = (data[0] & 0x04) != 0;
  	mLastExpansionReport.mLED1On			  = (data[0] & 0x10) != 0;
  	mLastExpansionReport.mLED2On			  = (data[0] & 0x20) != 0;
  	mLastExpansionReport.mLED3On			  = (data[0] & 0x40) != 0;
  	mLastExpansionReport.mLED4On			  = (data[0] & 0x80) != 0;
  
  	//two unknown bytes
  	mLastExpansionReport.mBatteryLevel = data[3];
  }
  
  void cWiiMote::ParseButtonReport(const unsigned char* data)
  {
  	//two bytes long
  	mLastButtonStatus.mA	 = (data[1] & 0x08) != 0;
  	mLastButtonStatus.mB	 = (data[1] & 0x04) != 0;
  	mLastButtonStatus.m1	 = (data[1] & 0x02) != 0;
  	mLastButtonStatus.m2	 = (data[1] & 0x01) != 0;
  	mLastButtonStatus.mPlus  = (data[0] & 0x10) != 0;
  	mLastButtonStatus.mMinus = (data[1] & 0x10) != 0;
  	mLastButtonStatus.mHome  = (data[1] & 0x80) != 0;
  	mLastButtonStatus.mUp	= (data[0] & 0x08) != 0;
  	mLastButtonStatus.mDown  = (data[0] & 0x04) != 0;
  	mLastButtonStatus.mLeft  = (data[0] & 0x01) != 0;
  	mLastButtonStatus.mRight = (data[0] & 0x02) != 0;
  }
  
  void cWiiMote::ParseMotionReport(const unsigned char* data)
  {
  	//three bytes long
  	mLastMotionReport.mX = data[0];
  	mLastMotionReport.mY = data[1];
  	mLastMotionReport.mZ = data[2];
  }
  
  void cWiiMote::PrintStatus() const
  {
  	float wX, wY, wZ;
  	float cX, cY, cZ;
  	float sX, sY;
  	float irX, irY;
  
  	wX = wY = wZ = cX = cY = cZ = sX = sY = irX = irY = 0.f;
  
  	GetCalibratedAcceleration(wX, wY, wZ);
  	printf("W:[%+1.2f %+1.2f %+1.2f] ", wX, wY, wZ);
  
  	if(mNunchuckAttached)
  	{
  		GetCalibratedChuckAcceleration(cX, cY, cZ);
  		printf("N:[%+1.2f %+1.2f %+1.2f] ", cX, cY, cZ);
  
  		GetCalibratedChuckStick(sX, sY);
  		printf("S:[%+1.2f %+1.2f] ", sX, sY);
  	}
  
  	if(mIRRunning)
  	{
  		if(GetIRP1(irX, irY))
  		{
  			printf("P1:[%+1.2f %+1.2f]", irX, irY);
  		}
  		if(GetIRP2(irX, irY))
  		{
  			printf("P2:[%+1.2f %+1.2f]", irX, irY);
  		}
  	}
  
  	//print the button status
  	if(mLastButtonStatus.m1)
  		printf("1");
  	if(mLastButtonStatus.m2)
  		printf("2");
  	if(mLastButtonStatus.mA)
  		printf("A");
  	if(mLastButtonStatus.mB)
  		printf("B");
  	if(mLastButtonStatus.mPlus)
  		printf("+");
  	if(mLastButtonStatus.mMinus)
  		printf("-");
  	if(mLastButtonStatus.mUp)
  		printf("U");
  	if(mLastButtonStatus.mDown)
  		printf("D");
  	if(mLastButtonStatus.mLeft)
  		printf("L");
  	if(mLastButtonStatus.mRight)
  		printf("R");
  	if(mLastButtonStatus.mHome)
  		printf("H");
  
  	if(mNunchuckAttached)
  	{
  		if(mLastChuckReport.mButtonZ)
  			printf("Z");
  		if(mLastChuckReport.mButtonC)
  			printf("C");
  	}
  
  	printf("\n");
  }
  
  bool cWiiMote::SelectInputChannel(bool continuous, unsigned char channel)
  {
  	ClearBuffer();
  	mOutputBuffer[0] = OUTPUT_CHANNEL_REPORT;
  	mOutputBuffer[1] = (continuous ? REQUEST_CONTINUOUS_REPORTS : REQUEST_SINGLE_REPORTS) | (mOutputControls.mVibration ? 0x1 : 0x0);
  	mOutputBuffer[2] = channel;
  	return mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize);
  }
  
  //this may or may not work to read buffers greater than 16 bytes. . . .
  bool cWiiMote::IssueReadRequest(unsigned int address, unsigned short size, unsigned char* buffer)
  {
  	bool retval = false;
  	if(mReadInfo.mReadStatus != tMemReadInfo::READ_PENDING)
  	{
  		ClearBuffer();
  		mOutputBuffer[0] = OUTPUT_READ_MEMORY;
  		mOutputBuffer[1] = (((address & 0xff000000) >> 24) & 0xFE) | (mOutputControls.mVibration ? 0x1 : 0x0);
  		mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
  		mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
  		mOutputBuffer[4] = (address & 0xff);
  
  		mOutputBuffer[5] = (size & 0xff00) >> 8;
  		mOutputBuffer[6] = (size & 0xff);
  
  		if(mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize))
  		{
  			mReadInfo.mReadStatus		= tMemReadInfo::READ_PENDING;
  			mReadInfo.mReadBuffer		= buffer;
  			mReadInfo.mTotalBytesToRead = size;
  			mReadInfo.mBytesRead		= 0;
  			mReadInfo.mBaseAddress		= (unsigned short)(address & 0xFFFF);
  			retval						= true;
  		}
  	}
  
  	return retval;
  }
  
  void cWiiMote::ParseReadData(const unsigned char* data)
  {
  	if(mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
  	{
  		const bool error = (data[0] & 0x0F) != 0;
  		if(error)
  		{
  			mReadInfo.mReadStatus = tMemReadInfo::READ_ERROR;
  		}
  		else
  		{
  			unsigned char bytes				  = (data[0] >> 4) + 1;
  			unsigned short offset			  = ((unsigned short)data[1] << 8) + data[2];
  			unsigned int space_left_in_buffer = mReadInfo.mTotalBytesToRead - mReadInfo.mBytesRead;
  			if(offset == mReadInfo.mBytesRead + mReadInfo.mBaseAddress && space_left_in_buffer >= bytes)
  			{
  				memcpy(&mReadInfo.mReadBuffer[mReadInfo.mBytesRead], &data[3], bytes);
  
  				mReadInfo.mBytesRead += bytes;
  				if(mReadInfo.mBytesRead >= mReadInfo.mTotalBytesToRead)
  				{
  					mReadInfo.mReadStatus = tMemReadInfo::READ_COMPLETE;
  				}
  			}
  		}
  	}
  }
  
  bool cWiiMote::ReadData(unsigned int address, unsigned short size, unsigned char* buffer)
  {
  	if(IssueReadRequest(address, size, buffer))
  	{
  		while(mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
  		{
  			if(!HeartBeat(1000))
  			{
  				break;
  			}
  		}
  	}
  	return mReadInfo.mReadStatus == tMemReadInfo::READ_COMPLETE;
  }
  
  bool cWiiMote::ReadCalibrationData()
  {
  	bool retval = false;
  	unsigned char buffer[CALIBRATION_DATA_LENGTH];
  	if(ReadData(CALIBRATION_ADDRESS, CALIBRATION_DATA_LENGTH, buffer))
  	{
  		mAccelCalibrationData.mXZero = buffer[0];
  		mAccelCalibrationData.mYZero = buffer[1];
  		mAccelCalibrationData.mZZero = buffer[2];
  		mAccelCalibrationData.mXG	= buffer[4];
  		mAccelCalibrationData.mYG	= buffer[5];
  		mAccelCalibrationData.mZG	= buffer[6];
  		retval						 = true;
  	}
  
  	return retval;
  }
  
  void cWiiMote::GetCalibratedAcceleration(float& x, float& y, float& z) const
  {
  	x = (mLastMotionReport.mX - mAccelCalibrationData.mXZero) / (float)(mAccelCalibrationData.mXG - mAccelCalibrationData.mXZero);
  	y = (mLastMotionReport.mY - mAccelCalibrationData.mYZero) / (float)(mAccelCalibrationData.mYG - mAccelCalibrationData.mYZero);
  	z = (mLastMotionReport.mZ - mAccelCalibrationData.mZZero) / (float)(mAccelCalibrationData.mZG - mAccelCalibrationData.mZZero);
  }
  
  void cWiiMote::GetCalibratedChuckAcceleration(float& x, float& y, float& z) const
  {
  	if(!mNunchuckAttached)
  	{
  		x = y = z = 0.f;
  		return;
  	}
  
  	x = (mLastChuckReport.mAccelX - mNunchuckAccelCalibrationData.mXZero) / (float)(mNunchuckAccelCalibrationData.mXG - mNunchuckAccelCalibrationData.mXZero);
  	y = (mLastChuckReport.mAccelY - mNunchuckAccelCalibrationData.mYZero) / (float)(mNunchuckAccelCalibrationData.mYG - mNunchuckAccelCalibrationData.mYZero);
  	z = (mLastChuckReport.mAccelZ - mNunchuckAccelCalibrationData.mZZero) / (float)(mNunchuckAccelCalibrationData.mZG - mNunchuckAccelCalibrationData.mZZero);
  }
  void cWiiMote::GetCalibratedChuckStick(float& x, float& y) const
  {
  	if(!mNunchuckAttached)
  	{
  		x = y = 0.f;
  		return;
  	}
  
  	if(mLastChuckReport.mStickX < mNunchuckStickCalibrationData.mXmid)
  	{
  		x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmin) / (float)(mNunchuckStickCalibrationData.mXmid - mNunchuckStickCalibrationData.mXmin)) - 1.f;
  	}
  	else
  	{
  		x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmid) / (float)(mNunchuckStickCalibrationData.mXmax - mNunchuckStickCalibrationData.mXmid));
  	}
  
  	if(mLastChuckReport.mStickY < mNunchuckStickCalibrationData.mYmid)
  	{
  		y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmin) / (float)(mNunchuckStickCalibrationData.mYmid - mNunchuckStickCalibrationData.mYmin)) - 1.f;
  	}
  	else
  	{
  		y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmid) / (float)(mNunchuckStickCalibrationData.mYmax - mNunchuckStickCalibrationData.mYmid));
  	}
  }
  
  bool cWiiMote::WriteMemory(unsigned int address, unsigned char size, const unsigned char* buffer)
  {
  	bool retval = false;
  	if(size <= 16)
  	{
  		ClearBuffer();
  		mOutputBuffer[0] = OUTPUT_WRITE_MEMORY;
  		mOutputBuffer[1] = (address & 0xff000000) >> 24 | (mOutputControls.mVibration ? 0x1 : 0x0);
  		mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
  		mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
  		mOutputBuffer[4] = (address & 0xff);
  		mOutputBuffer[5] = size;
  		memcpy(&mOutputBuffer[6], buffer, size);
  		retval = mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize);
  	}
  
  	return retval;
  }
  
  bool cWiiMote::InitNunchuck()
  {
  
  	bool retval = false;
  
  	//first init the nunchuck, if it is present
  	if(WriteMemory(NUNCHUCK_INIT_ADDRESS, 1, &NUNCHUCK_INIT_VAL))
  	{
  
  		unsigned char buffer[16];
  		//now try to read the nunchuck's calibration data
  		if(ReadData(NUNCHUCK_CALIBRATION_ADDRESS, 16, buffer))
  		{
  
  			//note that this hasn't worked properly for me yet (I get all 0xff).
  			/*mNunchuckAccelCalibrationData.mXZero = NunChuckByte(buffer[0]);
  			mNunchuckAccelCalibrationData.mYZero = NunChuckByte(buffer[1]);
  			mNunchuckAccelCalibrationData.mZZero = NunChuckByte(buffer[2]);
  
  			mNunchuckAccelCalibrationData.mXG = NunChuckByte(buffer[4]);
  			mNunchuckAccelCalibrationData.mYG = NunChuckByte(buffer[5]);
  			mNunchuckAccelCalibrationData.mZG = NunChuckByte(buffer[6]);
  
  			mNunchuckStickCalibrationData.mXmax = NunChuckByte(buffer[8]);
  			mNunchuckStickCalibrationData.mXmin = NunChuckByte(buffer[9]);
  			mNunchuckStickCalibrationData.mXmid = NunChuckByte(buffer[10]);
  			mNunchuckStickCalibrationData.mYmax = NunChuckByte(buffer[11]);
  			mNunchuckStickCalibrationData.mYmin = NunChuckByte(buffer[12]);
  			mNunchuckStickCalibrationData.mYmid = NunChuckByte(buffer[13]);*/
  
  			//these are default values from the wiili wiki
  			mNunchuckAccelCalibrationData.mXZero = 0x7E;
  			mNunchuckAccelCalibrationData.mYZero = 0x7A;
  			mNunchuckAccelCalibrationData.mZZero = 0x7D;
  			mNunchuckAccelCalibrationData.mXG	= 0xB0;
  			mNunchuckAccelCalibrationData.mYG	= 0xAF;
  			mNunchuckAccelCalibrationData.mZG	= 0xB1;
  			mNunchuckStickCalibrationData.mXmax  = 0xe5;
  			mNunchuckStickCalibrationData.mXmin  = 0x21;
  			mNunchuckStickCalibrationData.mXmid  = 0x7c;
  			mNunchuckStickCalibrationData.mYmax  = 0xe7;
  			mNunchuckStickCalibrationData.mYmin  = 0x23;
  			mNunchuckStickCalibrationData.mYmid  = 0x7a;
  			retval								 = true;
  		}
  	}
  	mNunchuckAttached = retval;
  	return retval;
  }
  
  void cWiiMote::ParseChuckReport(const unsigned char* data)
  {
  	mLastChuckReport.mStickX  = NunChuckByte(data[0]);
  	mLastChuckReport.mStickY  = NunChuckByte(data[1]);
  	mLastChuckReport.mAccelX  = NunChuckByte(data[2]);
  	mLastChuckReport.mAccelY  = NunChuckByte(data[3]);
  	mLastChuckReport.mAccelZ  = NunChuckByte(data[4]);
  	mLastChuckReport.mButtonC = (NunChuckByte(data[5]) & 0x2) == 0;
  	mLastChuckReport.mButtonZ = (NunChuckByte(data[5]) & 0x1) == 0;
  }
  
  bool cWiiMote::EnableIR()
  {
  	bool retval = false;
  
  	DisableIR();
  
  	if(!mIRRunning)
  	{
  		ClearBuffer();
  		mOutputBuffer[0] = OUTPUT_ENABLE_IR;
  		mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
  		retval			 = mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize);
  
  		if(retval)
  		{
  			mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
  			mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
  			retval			 = mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize);
  		}
  
  		if(retval)
  		{
  			unsigned char val = 0x1;
  			retval			  = WriteMemory(IR_REG_1, 1, &val);
  		}
  
  		if(retval)
  		{
  			retval = WriteMemory(IR_SENS_ADDR_1, 9, IR_SENS_MIDRANGE_PART1);
  		}
  
  		if(retval)
  		{
  			retval = WriteMemory(IR_SENS_ADDR_2, 2, IR_SENS_MIDRANGE_PART2);
  		}
  
  		if(retval)
  		{
  			retval = WriteMemory(IR_REG_2, 1, &IR_MODE_EXP);
  		}
  
  		if(retval)
  		{
  			unsigned char val = 0x8;
  			retval			  = WriteMemory(IR_REG_1, 1, &val);
  		}
  
  		mIRRunning = retval;
  	}
  	return retval;
  }
  
  bool cWiiMote::DisableIR()
  {
  	bool retval = false;
  
  	if(mIRRunning)
  	{
  		ClearBuffer();
  		mOutputBuffer[0] = OUTPUT_ENABLE_IR;
  		mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
  		retval			 = mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize);
  
  		if(retval)
  		{
  			mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
  			mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
  			retval			 = mHIDDevice.WriteToDevice(mOutputBuffer, mOutputBufferSize);
  		}
  
  		mIRRunning = false;
  	}
  	return retval;
  }
  
  void cWiiMote::ParseIRReport(const unsigned char* data)
  {
  	mLastIRReport.mP1X	= data[0] << 2 | (data[2] & 0x30) >> 4;
  	mLastIRReport.mP1Y	= data[1] << 2 | (data[2] & 0xc0) >> 6;
  	mLastIRReport.mP1Size = data[2] & 0xf;
  
  	mLastIRReport.mP2X	= data[3] << 2 | (data[5] & 0x30) >> 4;
  	mLastIRReport.mP2Y	= data[4] << 2 | (data[5] & 0xc0) >> 6;
  	mLastIRReport.mP2Size = data[5] & 0xf;
  
  	mLastIRReport.mP1Found = !(data[0] == 0xff && data[1] == 0xff && data[2] == 0xff);
  	mLastIRReport.mP2Found = !(data[3] == 0xff && data[4] == 0xff && data[5] == 0xff);
  }
  
  bool cWiiMote::GetIRP1(float& x, float& y) const
  {
  	bool retval = false;
  	if(mIRRunning && mLastIRReport.mP1Found)
  	{
  		x	  = mLastIRReport.mP1X / 1024.f;
  		y	  = mLastIRReport.mP1Y / 1024.f;
  		retval = true;
  	}
  	return retval;
  }
  
  bool cWiiMote::GetIRP2(float& x, float& y) const
  {
  	bool retval = false;
  	if(mIRRunning && mLastIRReport.mP2Found)
  	{
  		x	  = mLastIRReport.mP2X / 1024.f;
  		y	  = mLastIRReport.mP2Y / 1024.f;
  		retval = true;
  	}
  	return retval;
  }
  
  bool cWiiMote::StartDataStream()
  {
  	bool retval = false;
  
  	StopDataStream();
  
  	if(mNunchuckAttached)
  	{
  		retval = SetReportMode(REPORT_MODE_MOTION_CHUCK_IR);
  	}
  	else
  	{
  		retval = SetReportMode(REPORT_MODE_MOTION_IR);
  	}
  	EnableIR();
  
  	mDataStreamRunning = retval;
  	return retval;
  }
  
  bool cWiiMote::StopDataStream()
  {
  	if(mDataStreamRunning)
  	{
  		mDataStreamRunning = false;
  		DisableIR();
  		SetReportMode(REPORT_MODE_EVENT_BUTTONS);
  	}
  	return true;
  	;
  }
  #endif
  