/// <summary>
        /// 
        /// </summary>
        /// <param name="device"></param>
        /// <param name="address"></param>
        /// <param name="size"></param>
        internal void ReadAccCalibration(WiimoteDevice device)
        {
            UnityEngine.Debug.Log("ReadAccCalibration");


            //device.processingMode = ProcessingMode.AccCalibration;
          
            //request calibration
            ReadMemory(device, REGISTER_ACC_CALIBRATION, 7);


           

        }
        /// <summary>
        /// Handles setting up an extension when plugged in
        /// </summary>
        private void onReadExtension(WiimoteDevice device, byte[] buff)
        {

            UnityEngine.Debug.Log("onReadExtension");
            
            long type = ((long)buff[0] << 40) | ((long)buff[1] << 32) | ((long)buff[2]) << 24 | ((long)buff[3]) << 16 | ((long)buff[4]) << 8 | buff[5];


             if(type != (long)ExtensionNumber.Guitar && type!=(long)ExtensionNumber.Drums)
            type=type & 0x0000ffffffff;

            
             short numCalibrationBytes = 16;
             bool needCalibaration = true;

            switch((ExtensionNumber)type)
			{
				case ExtensionNumber.None:
				case ExtensionNumber.ParitallyInserted:
				     UnityEngine.Debug.Log("ParitallyInserted");
					//mWiimoteState.ExtensionType = ExtensionNumber.None;
					return;
				case ExtensionNumber.Nunchuk:
                    if (CheckExtensionExist(device, ExtensionType.Nunchuck))
                    {
                        device.isInProccesingExtension = false;
                        device.isReady = true;
                        return;
                    }

                    if (device.Mode == PassThruMode.Noone)
                    {
                        device.Extensions = (byte)ExtensionType.Nunchuck;
                    }
                    else
                    {
                        device.Extensions |= (byte)ExtensionType.Nunchuck;

                    }
                  //  UnityEngine.Debug.Log(mWiimoteState.NunchukState.CalibrationInfo.MaxX + " " + mWiimoteState.NunchukState.CalibrationInfo.MidX + " " + mWiimoteState.NunchukState.CalibrationInfo.MinX);
                 //   UnityEngine.Debug.Log(mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.X0 + " " + mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.XG);

                    break;
				case ExtensionNumber.ClassicController:
                    if (CheckExtensionExist(device, ExtensionType.ClassicController))
                    {
                        device.isReady = true;
                        device.isInProccesingExtension = false;
                        return; 
                    }

                    if (device.Mode == PassThruMode.Noone)
                    {
                        device.Extensions = (int)ExtensionType.ClassicController;
                    }
                    else
                    {
                        device.Extensions |= (int)ExtensionType.ClassicController;
                       // RegisterMode(device, PassThruMode.ClassicController);
                       
                    }

                        break;
				case ExtensionNumber.Guitar:
                     device.Extensions = (int)ExtensionType.Guitar;
                break;
				case ExtensionNumber.BalanceBoard:
                    device.Extensions = (int)ExtensionType.BalancedBoard;
	            break;
				case ExtensionNumber.Drums:
                    device.Extensions = (int)ExtensionType.Drums;
                break;
				case ExtensionNumber.TaikoDrum:
                     device.Extensions = (byte)ExtensionType.TaikoDrums;
                break;
				case ExtensionNumber.MotionPlus:
                if (CheckExtensionExist(device, ExtensionType.MotionPlus))
                {
                    device.isInProccesingExtension = false;
                    device.isReady = true;
                    return;
                }
                    
                     

                     if(device.Mode==PassThruMode.Noone)
                         device.Extensions = (byte)ExtensionType.MotionPlus;
                    else
                         device.Extensions |= (byte)ExtensionType.MotionPlus;

                     if (device.motionPlus != null && device.motionPlus.CalibrationInfo.MotionPlusCalibrated)
                     {
                         UnityEngine.Debug.Log("M+ already calibrated");
                         device.motionPlus.Enabled = true;
                         device.isReady = true;
                         needCalibaration = false;
                         device.isInProccesingExtension = false;
                     }else numCalibrationBytes = 32;

                    

					break;
				default:
					throw new Exception("Unknown extension controller found: " + type.ToString("x"));
			}

            UnityEngine.Debug.Log("Extension registered [" + (ExtensionNumber)type+"]");

            if (needCalibaration)
            {
                device.ExtensionForCalibration = (ExtensionNumber)type;

                ReadExtensionCalibaration(device, numCalibrationBytes);
            }
           

          
}
        protected void ReadExtensionCalibaration(WiimoteDevice device, short numCalibrationBytes)
        {

            UnityEngine.Debug.Log("ReadExtensionCalibaration");

            ReadMemory(device, REGISTER_EXTENSION_CALIBRATION, numCalibrationBytes);
                    
        }
        /// <summary>
        /// 
        /// </summary>
        internal void CheckMotionPlusCapabilities(WiimoteDevice device)
        {
               UnityEngine.Debug.Log("Try:"+device.numMPlusChecks+" to MOTIONPLUS_DETECT");

          
                  ReadMemory(device, REGISTER_MODE, 0x02);
              
        
        }
         /// <summary>
         /// Disable M+ and returns Status report
         /// </summary>
         /// <param name="device"></param>
        public void DisableMotionPlus(WiimoteDevice device)
        {
            device.Extensions &= (byte)0xDF;

            //Status Disabled
            device.motionPlus.Enabled=false;
           

             WriteMemory(device,REGISTER_EXTENSION_INIT1, 0x55);
            WriteMemory(device,REGISTER_EXTENSION_INIT2, 0x00);

           

           UnityEngine.Debug.Log(((device.Extensions & (byte)ExtensionType.MotionPlus) == 0)+ "MotionPlus disabled");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hidDevice"></param>
        /// <returns></returns>
        public IDevice ResolveDevice(IHIDDevice hidDevice)
        {


            if ((hidDevice.VID == VID && hidDevice.PID == PID) || (hidDevice.VID == VID && hidDevice.PID == PID_MOTION_PLUS_INSIDE))
            {
                _hidInterface = hidDevice.hidInterface;


                WiimoteDevice device;
                int inx = 0;


                // create new Device
                device = new WiimoteDevice(((IHIDInterface)_hidInterface).Generics.Count, hidDevice.PID, hidDevice.VID,hidDevice.ID, 16, 12, 4, 4, this);



                //inti button structure
                for (; inx < 12; inx++)
                {
                    device.Buttons[inx] = new ButtonDetails();
                }

                AxisDetails axisDetails;


                //AccX
                axisDetails = new AxisDetails();
                device.Axis[JoystickAxis.AxisAccX] = axisDetails;

                //AccY
                axisDetails = new AxisDetails();
                device.Axis[JoystickAxis.AxisAccY] = axisDetails;

                //AccZ
                axisDetails = new AxisDetails();
                device.Axis[JoystickAxis.AxisAccZ] = axisDetails;

                //AccR
                axisDetails = new AxisDetails();
                device.Axis[JoystickAxis.AxisAccR] = axisDetails;

                //AccU
                axisDetails = new AxisDetails();
                device.Axis[JoystickAxis.AxisAccU] = axisDetails;

                //AccV
                axisDetails = new AxisDetails();
                device.Axis[JoystickAxis.AxisAccV] = axisDetails;


                //LX
                axisDetails = new AxisDetails();
                //  axisDetails.max = 32767;
                //  axisDetails.min = -32767;
                device.Axis[JoystickAxis.AxisX] = axisDetails;

                //LY
                axisDetails = new AxisDetails();
                //    axisDetails.max = 32767;
                //    axisDetails.min = -32767;
                device.Axis[JoystickAxis.AxisY] = axisDetails;

                //RX
                axisDetails = new AxisDetails();
                //       axisDetails.max = 32767;
                //        axisDetails.min = -32767;
                device.Axis[JoystickAxis.AxisZ] = axisDetails;

                //RY
                axisDetails = new AxisDetails();
                //      axisDetails.max = 32767;
                //      axisDetails.min = -32767;
                device.Axis[JoystickAxis.AxisR] = axisDetails;


                //TRIGGERS
                axisDetails = new AxisDetails();
                axisDetails.max = 255;
                axisDetails.min = 0;
                axisDetails.isTrigger = true;
                device.Axis[JoystickAxis.AxisU] = axisDetails;


                axisDetails = new AxisDetails();
                axisDetails.max = 255;
                axisDetails.min = 0;
                axisDetails.isTrigger = true;
                device.Axis[JoystickAxis.AxisV] = axisDetails;

                //POV
                axisDetails = new AxisDetails();
                axisDetails.isHat = true;
                device.Axis[JoystickAxis.AxisPovX] = axisDetails;
                axisDetails = new AxisDetails();
                axisDetails.isHat = true;
                device.Axis[JoystickAxis.AxisPovY] = axisDetails;





               



                ((HIDDevice)hidDevice).InputReportByteLength = REPORT_LENGTH;
                ((HIDDevice)hidDevice).OutputReportByteLength = REPORT_LENGTH;

            
              

               

                return device;

            }


            return null;
        }
        /// <summary>
		/// Initialize the MotionPlus extension
		/// </summary>
		public void InitializeMotionPlus(WiimoteDevice device)
		{

          
           
          //  if ((device.Extensions & (byte)ExtensionType.MotionPlus) == 0 )
          //  {
                UnityEngine.Debug.Log("Initialize M+");

                //device.processingMode=ProcessingMode.InProgress;
                // Initialize it:
               
                 device.InitMotionPlus();

                device.isInProccesingExtension = false;

               // WriteData(REGISTER_MOTIONPLUS_INIT, 0x55);
                WriteMemory(device, REGISTER_MOTIONPLUS_INIT, 0x55, (suc) =>
                {

                    RegisterMode(device, PassThruMode.Noone);
                }

                    );

               

               
                 //device.processingMode=ProcessingMode.Update;
               

          //  }

		}
        /// <summary>
        /// Set the LEDs on the Wiimote
        /// </summary>
        /// <param name="led1">LED 1</param>
        /// <param name="led2">LED 2</param>
        /// <param name="led3">LED 3</param>
        /// <param name="led4">LED 4</param>
        internal void SetLEDs(WiimoteDevice device, bool led1, bool led2, bool led3, bool led4)
        {
            device.LED[0] = led1;
            device.LED[1] = led2;
            device.LED[2] = led3;
            device.LED[3] = led4;
            //mWiimoteState.LEDState.LED1 = led1;
            //mWiimoteState.LEDState.LED2 = led2;
            //mWiimoteState.LEDState.LED3 = led3;
            //mWiimoteState.LEDState.LED4 = led4;

            byte[] mBuff = new byte[REPORT_LENGTH];
            
            mBuff[0] = (byte)OutputReport.LEDs;
            mBuff[1] = (byte)(
                (led1 ? (uint)0x10 : (uint)0x00) |
                (led2 ? (uint)0x20 : (uint)0x00) |
                (led3 ? (uint)0x40 : (uint)0x00) |
                (led4 ? (uint)0x80 : (uint)0x00) |
                        device.RumbleBit);

            _hidInterface.Write(mBuff, device.ID);
        }
        /// <summary>
        /// Set the LEDs on the Wiimote
        /// </summary>
        /// <param name="leds">The value to be lit up in base2 on the Wiimote</param>
        internal void SetLEDs(WiimoteDevice device, int leds)
        {




            device.LED[0] = (leds & 0x01) > 0;
            device.LED[1] = (leds & 0x02) > 0;
            device.LED[2] = (leds & 0x04) > 0;
            device.LED[3] = (leds & 0x08) > 0;


            //mWiimoteState.LEDState.LED1 = (leds & 0x01) > 0;
            //mWiimoteState.LEDState.LED2 = (leds & 0x02) > 0;
            //mWiimoteState.LEDState.LED3 = (leds & 0x04) > 0;
            //mWiimoteState.LEDState.LED4 = (leds & 0x08) > 0;


            byte[] mBuff = new byte[REPORT_LENGTH];

            mBuff[0] = (byte)OutputReport.LEDs;
            mBuff[1] = (byte)(
                ((leds & 0x01) > 0 ? (uint)0x10 : (uint)0x00) |
                ((leds & 0x02) > 0 ? (uint)0x20 : (uint)0x00) |
                ((leds & 0x04) > 0 ? (uint)0x40 : (uint)0x00) |
                ((leds & 0x08) > 0 ? (uint)0x80 : (uint)0x00) |
                        (uint)device.RumbleBit);

            _hidInterface.Write(mBuff, device.ID);
        }
 internal void SetMode(WiimoteDevice device ,PassThruMode mode)
 {
     if (mode == PassThruMode.Noone)
     {
        //TODO
     }else if(mode == PassThruMode.ClassicController)
     {
         //TODO
     }
     else if (mode == PassThruMode.Nunchuck)
     {
         //TODO
     }
 }
        /// <summary>
        /// handles calibration read information stored on Wiimote
        /// </summary>
        private void onReadAccCalibration(WiimoteDevice device,byte[] buff)
        {
            UnityEngine.Debug.Log("onReadAccCalibration");
          

                // AxisDetails[JoystickAxis.AxisX].
                AxisDetails axisDetails;

                axisDetails = device.Axis[JoystickAxis.AxisAccX] as AxisDetails;
                axisDetails.min = buff[0];
                axisDetails.max = buff[4];

                axisDetails = device.Axis[JoystickAxis.AxisAccY] as AxisDetails;
                axisDetails.min = buff[1];
                axisDetails.max = buff[5];

                axisDetails = device.Axis[JoystickAxis.AxisAccZ] as AxisDetails;
                axisDetails.min = buff[2];
                axisDetails.max = buff[6];

                //00-00-60-00-16-80-80-7F-17-99-99-98
                //mWiimoteState.AccelCalibrationInfo.X0 = buff[0];
                //mWiimoteState.AccelCalibrationInfo.Y0 = buff[1];
                //mWiimoteState.AccelCalibrationInfo.Z0 = buff[2];
                //mWiimoteState.AccelCalibrationInfo.XG = buff[4];
                //mWiimoteState.AccelCalibrationInfo.YG = buff[5];
                //mWiimoteState.AccelCalibrationInfo.ZG = buff[6];


                device.isAccCalibrated = true;


          
               GetStatus(device);
          

        }
        public void SetReportType2(WiimoteDevice device,InputReport type, bool continuous)
        {
            byte[] mBuff = new byte[REPORT_LENGTH];

            mBuff[0] = (byte)OutputReport.Type;
            // mBuff[1] = (byte)((continuous ? 0x04 : 0x00) | (byte)(mWiimoteState.Rumble ? 0x01 : 0x00));
            mBuff[1] = (byte)((continuous ? (uint)0x04 : (uint)0x00) | (uint)device.RumbleBit);
            mBuff[2] =(byte)type;

            _hidInterface.Write(mBuff, device.ID, (suc) => { 
                _hidInterface.Read(device.ID,onRead); });
        }
        /// <summary>
        /// Set Wiimote reporting mode
        /// </summary>
        /// <param name="type">Report type</param>
        /// <param name="irSensitivity">IR sensitivity</param>
        /// <param name="continuous">Continuous data</param>
        void SetReportType(WiimoteDevice device, InputReport type, IRSensitivity irSensitivity, bool continuous)
        {
            switch (type)
            {
                case InputReport.ButtonsIRAccel:
                    EnableIR(device, IRMode.Extended, irSensitivity);
                    break;
                case InputReport.ButtonsIRExtensionAccel:
                    EnableIR(device, IRMode.Basic, irSensitivity);
                    break;
                default:
                    DisableIR(device);
                    break;
            }


            UnityEngine.Debug.Log("SyncType");

            byte[] mBuff = new byte[REPORT_LENGTH];

            mBuff[0] = (byte)OutputReport.Type;
            // mBuff[1] = (byte)((continuous ? 0x04 : 0x00) | (byte)(mWiimoteState.Rumble ? 0x01 : 0x00));
            mBuff[1] = (byte)((continuous ? (uint)0x04 : (uint)0x00) | (uint)device.RumbleBit);
            mBuff[2] = (byte)type;

            _hidInterface.Write(mBuff, device.ID);
        }
        ///// <summary>
        ///// Returns whether rumble is currently enabled.
        ///// </summary>
        ///// <returns>Byte indicating true (0x01) or false (0x00)</returns>
        //private byte GetRumbleBit(WiimoteDevice device)
        //{
        //    //return (byte)(mWiimoteState.Rumble ? 0x01 : 0x00);
        //    return (byte)(device.Rumble ? 0x01 : 0x00);
        //}

     
        /// <summary>
        /// Set Wiimote reporting mode (if using an IR report type, IR sensitivity is set to WiiLevel3)
        /// </summary>
        /// <param name="type">Report type</param>
        /// <param name="continuous">Continuous data</param>
        void SetReportType(WiimoteDevice device, InputReport type, bool continuous)
        {
            SetReportType(device, type, IRSensitivity.Maximum, continuous);
        }
 /// <summary>
 /// Write a single byte to the Wiimote
 /// </summary>
 /// <param name="address">Address to write</param>
 /// <param name="data">Byte to write</param>
 void WriteMemory(WiimoteDevice device, int address, byte data,HIDDevice.WriteCallback callback = null)
 {
     WriteMemory(device, address, 1, new byte[] { data },callback);
 }
        /// <summary>
        /// Toggle rumble
        /// </summary>
        /// <param name="on">On or off</param>
        internal void SetRumble(WiimoteDevice device, bool on)
        {
            device.Rumble = on;

            // the LED report also handles rumble
            SetLEDs(device, device.LED[0],
                    device.LED[1],
                    device.LED[2],
                    device.LED[3]);
        }
        /// <summary>
        /// Write a byte array to a specified address
        /// </summary>
        /// <param name="address">Address to write</param>
        /// <param name="size">Length of buffer</param>
        /// <param name="data">Data buffer</param>

        void WriteMemory(WiimoteDevice device, int address, byte size, byte[] data, HIDDevice.WriteCallback callback = null)
        {

            byte[] mBuff = new byte[REPORT_LENGTH];
            
            mBuff[0] = (byte)OutputReport.WriteMemory;
            mBuff[1] = (byte)(((address & 0xff000000) >> 24) | device.RumbleBit);
            mBuff[2] = (byte)((address & 0x00ff0000) >> 16);
            mBuff[3] = (byte)((address & 0x0000ff00) >> 8);
            mBuff[4] = (byte)(address & 0x000000ff);
            mBuff[5] = size;


            Array.Copy(data, 0, mBuff, 6, size);



            if (callback == null)
                _hidInterface.Write(mBuff, device.ID);
            else
                _hidInterface.Write(mBuff, device.ID, callback);

        }
        /// <summary>
        /// Retrieve the current status of the Wiimote and extensions.  
        /// </summary>
        void GetStatus(WiimoteDevice device)
        {

            UnityEngine.Debug.Log("GetStatus");

            HIDDevice hidDevice = _hidInterface.Generics[device.ID];
            hidDevice.InputReportByteLength = REPORT_LENGTH;
            hidDevice.OutputReportByteLength = REPORT_LENGTH;

            byte[] mBuff = new byte[REPORT_LENGTH];

            mBuff[0] = (byte)OutputReport.Status;
            mBuff[1] = (byte)device.RumbleBit;
           

            _hidInterface.Write(mBuff, device.ID);

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="device"></param>
        /// <param name="buff"></param>
        /// <param name="offset"></param>
        private void CalibrateMotionPlus(WiimoteDevice device, byte[] buff, int offset)
        {

            device.motionPlus.RawValues.z = (buff[offset + 0] | (buff[offset + 3] & 0xfc) << 6);//YAW
            device.motionPlus.RawValues.y = (buff[offset + 1] | (buff[offset + 4] & 0xfc) << 6);//ROLL
            device.motionPlus.RawValues.x = (buff[offset + 2] | (buff[offset + 5] & 0xfc) << 6);//PITCH



            if (!device.motionPlus.CalibrationInfo.MotionPlusCalibrated)
            {

                device.UpdateMPlusCalibration(device.motionPlus.RawValues);

                if (device.motionPlus.CalibrationInfo.MotionPlusCalibrated)
                {
                    device.isReady = true;
                    device.isInProccesingExtension = false;
                    UnityEngine.Debug.Log("BIAS:" + device.motionPlus.CalibrationInfo.mBias.x + " " + device.motionPlus.CalibrationInfo.mBias.y + " " + device.motionPlus.CalibrationInfo.mBias.z);
                }


                return;
            }

          

         
        }
        /// <summary>
        /// Turn on the IR sensor
        /// </summary>
        /// <param name="mode">The data report mode</param>
        /// <param name="irSensitivity">IR sensitivity</param>
        void EnableIR(WiimoteDevice device, IRMode mode, IRSensitivity irSensitivity)
        {
            device.irMode = mode;

            UnityEngine.Debug.Log("Sync1");

            byte[] mBuff = new byte[REPORT_LENGTH];
            mBuff[0] = (byte)OutputReport.IR;
            mBuff[1] = (byte)(0x04 | device.RumbleBit);
            _hidInterface.Write(mBuff, device.ID);

            UnityEngine.Debug.Log("Sync2");
            Array.Clear(mBuff, 0, mBuff.Length);
            mBuff = new byte[REPORT_LENGTH];
            mBuff[0] = (byte)OutputReport.IR2;
            mBuff[1] = (byte)(0x04 | device.RumbleBit);
            _hidInterface.Write(mBuff, device.ID);


            UnityEngine.Debug.Log("Sync3");
            WriteMemory(device, REGISTER_IR, 0x08);

            UnityEngine.Debug.Log("Sync2x");
            setSensitivity(device,irSensitivity);

            UnityEngine.Debug.Log("Sync4");
            WriteMemory(device, REGISTER_IR_MODE, (byte)mode);

            UnityEngine.Debug.Log("Sync5");
            WriteMemory(device, REGISTER_IR, 0x08);

       
       
        }
        internal void RegisterMode(WiimoteDevice device, PassThruMode mode)
        {
            

            WriteMemory(device, REGISTER_MODE, (byte)mode);

          
        }
        void setSensitivity(WiimoteDevice device, IRSensitivity irSensitivity)
        {

             switch (irSensitivity)
            {
                case IRSensitivity.WiiLevel1:
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_1, 9, new byte[] { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0x64, 0x00, 0xfe });
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_2, 2, new byte[] { 0xfd, 0x05 });
                    break;
                case IRSensitivity.WiiLevel2:
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_1, 9, new byte[] { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0x96, 0x00, 0xb4 });
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_2, 2, new byte[] { 0xb3, 0x04 });
                    break;
                case IRSensitivity.WiiLevel3:
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_1, 9, new byte[] { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64 });
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_2, 2, new byte[] { 0x63, 0x03 });
                    break;
                case IRSensitivity.WiiLevel4:
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_1, 9, new byte[] { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xc8, 0x00, 0x36 });
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_2, 2, new byte[] { 0x35, 0x03 });
                    break;
                case IRSensitivity.WiiLevel5:
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_1, 9, new byte[] { 0x07, 0x00, 0x00, 0x71, 0x01, 0x00, 0x72, 0x00, 0x20 });
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_2, 2, new byte[] { 0x1, 0x03 });
                    break;
                case IRSensitivity.Maximum:

                    UnityEngine.Debug.Log("Sync2x1");
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_1, 9, new byte[] { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0x90, 0x00, 0x41 });
                    UnityEngine.Debug.Log("Sync2x2");
                    WriteMemory(device, REGISTER_IR_SENSITIVITY_2, 2, new byte[] { 0x40, 0x00 });
                    break;
                default:
                    throw new ArgumentOutOfRangeException("irSensitivity");
            }




          


        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="device"></param>
        /// <param name="buff"></param>
        public void onCheckMotionPlusCapabilities(WiimoteDevice device,byte[] buff)
        {
            UnityEngine.Debug.Log("onCheckMotionPlusCapabilities");
                
            if(buff[1] == 0x05){
                

                InitializeMotionPlus(device);
                 //device.processingMode=ProcessingMode.MPlusInit;
            }else{
                if(device.numMPlusChecks<4){
                     device.numMPlusChecks++;

                     Thread.Sleep(1000);
                    //device.processingMode=ProcessingMode.MPlusCheck;

                     CheckMotionPlusCapabilities(device);
                 }else{
                    // device.processingMode=ProcessingMode.Update;
                     device.isReady = true;

                    
                    if(device.DataReportType!=(byte)InputReport.ButtonsIRExtensionAccel)
                     SetReportType(device, InputReport.ButtonsIRExtensionAccel, true);
                }
                 
            }

        }
        /// <summary>
        /// Disable the IR sensor
        /// </summary>
        void DisableIR(WiimoteDevice device)
        {
            device.irMode = IRMode.Off;

            byte[] mBuff=new byte[27];
            mBuff[0] = (byte)OutputReport.IR;
            mBuff[1] = (byte)device.RumbleBit;

            _hidInterface.Write(mBuff, device.ID, (suc) => {
                 mBuff = new byte[27];
                mBuff[0] = (byte)OutputReport.IR2;
                mBuff[1] = (byte)device.RumbleBit;
                _hidInterface.Write(mBuff, device.ID);
            });

           

            
            
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="device"></param>
       private void ReadExtension(WiimoteDevice device){
           UnityEngine.Debug.Log("ReadExtension");

           ReadMemory(device, REGISTER_EXTENSION_TYPE, 6);
               
       }
        /// <summary>
        /// Read data or register from Wiimote
        /// </summary>
        /// <param name="address">Address to read</param>
        /// <param name="size">Length to read</param>

        void ReadMemory(WiimoteDevice device, int address, short size, HIDDevice.WriteCallback callback)
        {

            //Output Report 0x17 reads memory:
            //(52) 17 XX XX XX XX YY YY
            //XX XX XX XX is big-endian formatted address
            //YY YY is big-endian formatted size in bytes
            //LSB of first byte is rumble flag and is not part of address, should
            //be set to whatever state the rumble should be

            byte[] mBuff = new byte[REPORT_LENGTH];
           
            mBuff[0] = (byte)OutputReport.ReadMemory;
            mBuff[1] = (byte)(((address & 0xff000000) >> 24) | (uint)device.RumbleBit);
            mBuff[2] = (byte)((address & 0x00ff0000) >> 16);
            mBuff[3] = (byte)((address & 0x0000ff00) >> 8);
            mBuff[4] = (byte)(address & 0x000000ff);

            mBuff[5] = (byte)((size & 0xff00) >> 8);
            mBuff[6] = (byte)(size & 0xff);

        
            _hidInterface.Write(mBuff,device.ID, callback);

           
           

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="device"></param>
        /// <param name="extensionType"></param>
        /// <returns></returns>
        private bool CheckExtensionExist(WiimoteDevice device, ExtensionType extensionType)
        {
            if ((device.Extensions & (byte)extensionType)!= 0)
            {
                UnityEngine.Debug.Log("Double package. Extesnion" + extensionType + " already registered");
                return true;
            }

            return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="device"></param>
        /// <param name="address"></param>
        /// <param name="size"></param>
        void ReadMemory(WiimoteDevice device, int address, short size)
        {

            byte[] mBuff = new byte[REPORT_LENGTH];

            mBuff[0] = (byte)OutputReport.ReadMemory;
            mBuff[1] = (byte)(((address & 0xff000000) >> 24) | (uint)device.RumbleBit);
            mBuff[2] = (byte)((address & 0x00ff0000) >> 16);
            mBuff[3] = (byte)((address & 0x0000ff00) >> 8);
            mBuff[4] = (byte)(address & 0x000000ff);

            mBuff[5] = (byte)((size & 0xff00) >> 8);
            mBuff[6] = (byte)(size & 0xff);

            _hidInterface.Write(mBuff, device.ID);


        }
        protected void onExtensionCalibration(WiimoteDevice device,byte[] buff)
        {

            UnityEngine.Debug.Log("onExtensionCalibration");
                
            AxisDetails axisDetails;

            switch(device.ExtensionForCalibration)
			{
				
				case ExtensionNumber.Nunchuk:

            
                    //X0,Y0,Z0 are actully MID
                    //XG,YG,ZG are actually MAX
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.X0 = buff[0];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.Y0 = buff[1];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.Z0 = buff[2];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.XG = buff[4];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.YG = buff[5];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.ZG = buff[6];
                    //mWiimoteState.NunchukState.CalibrationInfo.MaxX = buff[8]; //seem this calibration isn't correct
                    //mWiimoteState.NunchukState.CalibrationInfo.MinX = buff[9];
                    //mWiimoteState.NunchukState.CalibrationInfo.MidX = buff[10];
                    //mWiimoteState.NunchukState.CalibrationInfo.MaxY = buff[11];
                    //mWiimoteState.NunchukState.CalibrationInfo.MinY = buff[12];
                    //mWiimoteState.NunchukState.CalibrationInfo.MidY = buff[13];
         


                    //X,Y
                    axisDetails = device.Axis[JoystickAxis.AxisX] as AxisDetails;
                    axisDetails.max = buff[8];
                    axisDetails.min = buff[9];
                    axisDetails.mid = buff[10];

                    axisDetails = device.Axis[JoystickAxis.AxisY] as AxisDetails;
                    axisDetails.max = buff[11];
                    axisDetails.min = buff[12];
                    axisDetails.mid = buff[13];



                    // Acceleration
                    axisDetails = device.Axis[JoystickAxis.AxisAccR] as AxisDetails;
                    axisDetails.max = buff[4];
                    axisDetails.min = buff[0];


                    axisDetails = device.Axis[JoystickAxis.AxisAccU] as AxisDetails;
                    axisDetails.max = buff[5];
                    axisDetails.min = buff[1];


                    axisDetails = device.Axis[JoystickAxis.AxisAccV] as AxisDetails;
                    axisDetails.max = buff[6];
                    axisDetails.min = buff[2];


                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.X0 = buff[0];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.Y0 = buff[1];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.Z0 = buff[2];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.XG = buff[4];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.YG = buff[5];
                    //mWiimoteState.NunchukState.CalibrationInfo.AccelCalibration.ZG = buff[6];

                    //mWiimoteState.NunchukState.CalibrationInfo.MaxX = buff[8];
                    //mWiimoteState.NunchukState.CalibrationInfo.MinX = buff[9];
                    //mWiimoteState.NunchukState.CalibrationInfo.MidX = buff[10];
                    //mWiimoteState.NunchukState.CalibrationInfo.MaxY = buff[11];
                    //mWiimoteState.NunchukState.CalibrationInfo.MinY = buff[12];
                    //mWiimoteState.NunchukState.CalibrationInfo.MidY = buff[13];


                    device.isInProccesingExtension = false;
                    device.isReady = true;

                    break;
                case ExtensionNumber.ClassicController:

                    //Left Stick
                    axisDetails = device.Axis[JoystickAxis.AxisX] as AxisDetails;
                    axisDetails.max = (byte)(buff[0] >> 2);
                    axisDetails.min = (byte)(buff[1] >> 2);
                    axisDetails.mid = (byte)(buff[2] >> 2);

                    axisDetails = device.Axis[JoystickAxis.AxisY] as AxisDetails;
                    axisDetails.max = (byte)(buff[3] >> 2);
                    axisDetails.min = (byte)(buff[4] >> 2);
                    axisDetails.mid = (byte)(buff[5] >> 2);

                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MaxXL = (byte)(buff[0] >> 2);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MinXL = (byte)(buff[1] >> 2);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MidXL = (byte)(buff[2] >> 2);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MaxYL = (byte)(buff[3] >> 2);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MinYL = (byte)(buff[4] >> 2);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MidYL = (byte)(buff[5] >> 2);

                    //Rigth Stick
                    axisDetails = device.Axis[JoystickAxis.AxisZ] as AxisDetails;
                    axisDetails.max = (byte)(buff[6] >> 3);
                    axisDetails.min = (byte)(buff[7] >> 3);
                    axisDetails.mid = (byte)(buff[8] >> 3);

                    axisDetails = device.Axis[JoystickAxis.AxisR] as AxisDetails;
                    axisDetails.max = (byte)(buff[9] >> 3);
                    axisDetails.min = (byte)(buff[10] >> 3);
                    axisDetails.mid = (byte)(buff[11] >> 3);

                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MaxXR = (byte)(buff[6] >> 3);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MinXR = (byte)(buff[7] >> 3);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MidXR = (byte)(buff[8] >> 3);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MaxYR = (byte)(buff[9] >> 3);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MinYR = (byte)(buff[10] >> 3);
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MidYR = (byte)(buff[11] >> 3);

                    // this doesn't seem right...
                    //					mWiimoteState.ClassicControllerState.AccelCalibrationInfo.MinTriggerL = (byte)(buff[12] >> 3);
                    //					mWiimoteState.ClassicControllerState.AccelCalibrationInfo.MaxTriggerL = (byte)(buff[14] >> 3);
                    //					mWiimoteState.ClassicControllerState.AccelCalibrationInfo.MinTriggerR = (byte)(buff[13] >> 3);
                    //					mWiimoteState.ClassicControllerState.AccelCalibrationInfo.MaxTriggerR = (byte)(buff[15] >> 3);

                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MinTriggerL = 0;
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MaxTriggerL = 31;
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MinTriggerR = 0;
                    //mWiimoteState.ClassicControllerState.CalibrationInfo.MaxTriggerR = 31;

                    //Left Trigger
                    axisDetails = device.Axis[JoystickAxis.AxisU] as AxisDetails;
                    axisDetails.max = (byte)(buff[14] >> 3);
                    axisDetails.min = (byte)(buff[12] >> 3);

                    //Rigth Trigger
                    axisDetails = device.Axis[JoystickAxis.AxisV] as AxisDetails;
                    axisDetails.max = (byte)(buff[15] >> 3);
                    axisDetails.min = (byte)(buff[13] >> 3);

                    device.isInProccesingExtension = false;
                    device.isReady = true;
                    break;



                case ExtensionNumber.MotionPlus:
                    //Not known to me...

                    device.motionPlus.Enabled = true;

                 break;

            }


            device.ExtensionForCalibration = 0;

           //if (device.DataReportType != (byte)InputReport.ButtonsIRExtensionAccel)
            SetReportType(device,InputReport.ButtonsIRExtensionAccel,true);

          

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="device"></param>
        internal void ClearExtension(WiimoteDevice device)
        {
           // device.processingMode = ProcessingMode.ClearExtension;

            UnityEngine.Debug.Log("ClearExtension");
            
            WriteMemory(device, REGISTER_EXTENSION_INIT1, 0x55);
           
        

            WriteMemory(device, REGISTER_EXTENSION_INIT2, 0x00, (suc) =>
               {
                 

                   ReadAccCalibration(device);


               });
        }