/// <summary>
 /// http://wiibrew.org/index.php?title=Wiimote#Extended_Mode
 /// </summary>
 protected static bool ParseExtendedBeacon(byte[] buff, int offset, ExtendedIRBeacon irBeacon)
 {
     if (buff[offset + 0] == 0xff && buff[offset + 1] == 0xff && buff[offset + 2] == 0xff)
     {
         return(false);
     }
     irBeacon.X    = buff[offset + 0] | ((buff[offset + 2] >> 4) & 0x03) << 8;
     irBeacon.Y    = buff[offset + 1] | ((buff[offset + 2] >> 6) & 0x03) << 8;
     irBeacon.Size = buff[offset + 2] & 0x0f;
     return(true);
 }
        protected override bool ParseReport(byte[] report)
        {
            if (report[0] < 0x20)
                throw new InvalidOperationException("Received an output report!");
            InputReport type = (InputReport)report[0];
            if (type >= InputReport.Buttons && type <= InputReport.ButtonsAccelerometer36IrB)
            {
                if (type == InputReport.ButtonsAccelerometer36IrB)
                    ReportingMode = ReportingMode.ButtonsAccelerometer36Ir;
                else
                    ReportingMode = (ReportingMode)type;

                IRMode irMode = GetIrMode(type);
                if (this._IrMode != irMode)
                {
                    for (int i = 0; i < _CachedIRBeacons.Length; i++)
                    {
                        BasicIRBeacon newBeacon = null;
                        switch (irMode)
                        {
                            case IRMode.Basic:
                                newBeacon = new BasicIRBeacon();
                                break;
                            case IRMode.Extended:
                                newBeacon = new ExtendedIRBeacon();
                                break;
                            case IRMode.Full:
                                newBeacon = new FullIRBeacon();
                                break;
                        }
                        _CachedIRBeacons[i] = newBeacon;
                        _IRBeacons[i] = null;
                    }
                    this._IrMode = irMode;
                }
            }
            switch (type)
            {
                case InputReport.Buttons:
                    ParseButtons(report, 1);
                    break;
                case InputReport.ButtonsAccelerometer:
                    ParseButtons(report, 1);
                    ParseAccelerometer(report, 3);
                    break;
                case InputReport.Buttons8Extension:
                    ParseButtons(report, 1);
                    ParseExtension(report, 3, 8);
                    break;
                case InputReport.ButtonsAccelerometer12Ir:
                    {
                        ParseButtons(report, 1);
                        ParseAccelerometer(report, 3);

                        ExtendedIRBeacon irBeacon;

                        // Parse beacon 0.
                        irBeacon = (ExtendedIRBeacon)_CachedIRBeacons[0];
                        _IRBeacons[0] = ParseExtendedBeacon(report, 6, irBeacon) ? irBeacon : null;

                        // Parse beacon 1.
                        irBeacon = (ExtendedIRBeacon)_CachedIRBeacons[1];
                        _IRBeacons[1] = ParseExtendedBeacon(report, 9, irBeacon) ? irBeacon : null;

                        // Parse beacon 2.
                        irBeacon = (ExtendedIRBeacon)_CachedIRBeacons[2];
                        _IRBeacons[2] = ParseExtendedBeacon(report, 12, irBeacon) ? irBeacon : null;

                        // Parse beacon 3.
                        irBeacon = (ExtendedIRBeacon)_CachedIRBeacons[3];
                        _IRBeacons[3] = ParseExtendedBeacon(report, 15, irBeacon) ? irBeacon : null;
                    }
                    break;
                case InputReport.Buttons19Extension:
                    ParseButtons(report, 1);
                    ParseExtension(report, 3, 19);
                    break;
                case InputReport.ButtonsAccelerometer16Extension:
                    ParseButtons(report, 1);
                    ParseAccelerometer(report, 3);
                    ParseExtension(report, 6, 16);
                    break;
                case InputReport.Buttons10Ir9Extension:
                case InputReport.ButtonsAccelerometer10Ir6Extension:
                    {
                        int offset = 1;
                        offset += ParseButtons(report, offset);
                        if (type == InputReport.ButtonsAccelerometer10Ir6Extension)
                            offset += ParseAccelerometer(report, offset);

                        BasicIRBeacon irBeacon;

                        // Parse beacon 0.
                        irBeacon = _CachedIRBeacons[0];
                        _IRBeacons[0] = ParseBasicBeacon(report, offset, 0, irBeacon) ? irBeacon : null;

                        // Parse beacon 1.
                        irBeacon = _CachedIRBeacons[1];
                        _IRBeacons[1] = ParseBasicBeacon(report, offset, 1, irBeacon) ? irBeacon : null;

                        // Parse beacon 2.
                        irBeacon = _CachedIRBeacons[2];
                        _IRBeacons[2] = ParseBasicBeacon(report, offset + 5, 0, irBeacon) ? irBeacon : null;

                        // Parse beacon 3.
                        irBeacon = _CachedIRBeacons[3];
                        _IRBeacons[3] = ParseBasicBeacon(report, offset + 5, 1, irBeacon) ? irBeacon : null;

                        offset += 10; // Each pair of IR-beacons is 5 bytes.

                        if (type == InputReport.ButtonsAccelerometer10Ir6Extension)
                            ParseExtension(report, offset, 6);
                        else
                            ParseExtension(report, offset, 9);
                    }
                    break;
                case InputReport.Extension:
                    ParseExtension(report, 1, 21);
                    break;
                case InputReport.ButtonsAccelerometer36IrA:
                    {
                        ParseButtons(report, 1); // since button information is complete on both the interlaced reports it needs no temporary storage

                        _PartialAccelerometerX = report[3];
                        _PartialAccelerometerZ = (ushort)(((report[2] & 0x60) << 1) | ((report[1] & 0x60) >> 1));

                        _PartialIRBeaconOneResult = ParseFullBeacon(report, 4, (FullIRBeacon)_CachedIRBeacons[0]);
                        _PartialIRBeaconTwoResult = ParseFullBeacon(report, 13, (FullIRBeacon)_CachedIRBeacons[1]);
                    }
                    break;
                case InputReport.ButtonsAccelerometer36IrB:
                    {
                        ParseButtons(report, 1);

                        // Complete the _PartialAccelerometerZ field
                        _PartialAccelerometerZ = (ushort)(_PartialAccelerometerZ | ((report[2] & 60) >> 3) | ((report[1] & 60) >> 5));

                        // Initialize the accelerometer if it was not yet initialized (should never happen).
                        if (Accelerometer == null)
                            ReadCalibrationData();

                        // Construct the new accelerometer-values from now completed data
                        Accelerometer.Raw.X = _PartialAccelerometerX;
                        Accelerometer.Raw.Y = report[3];
                        Accelerometer.Raw.Z = _PartialAccelerometerZ;

                        UpdateCalibratedAccelerometer();

                        FullIRBeacon irBeacon;

                        // Commit partial irbeacon from 'a' report
                        IRBeacons[0] = _PartialIRBeaconOneResult ? _CachedIRBeacons[0] : null;

                        // Commit partial irbeacon from 'a' report
                        IRBeacons[1] = _PartialIRBeaconTwoResult ? _CachedIRBeacons[1] : null;

                        // Parse beacon 2.
                        irBeacon = (FullIRBeacon)_CachedIRBeacons[2];
                        IRBeacons[2] = ParseFullBeacon(report, 4, irBeacon) ? irBeacon : null;

                        // Parse beacon 3.
                        irBeacon = (FullIRBeacon)_CachedIRBeacons[3];
                        IRBeacons[3] = ParseFullBeacon(report, 13, irBeacon) ? irBeacon : null;
                    }
                    break;

                case InputReport.GetStatusResult:
                    ParseButtons(report, 1);
                    ParseStatus(report);
                    break;
                case InputReport.ReadDataResult:
                    ParseButtons(report, 1);
                    // The rest is handled by the ReadData method (waiting for the report).
                    break;
                case InputReport.WriteDataResult:
                    // The rest is handled by the WriteData method (waiting for the report).
                    break;
                default:
                    Debug.WriteLine("Unknown report type: " + type.ToString("x"));
                    return false;
            }

            if ((type >= InputReport.Buttons || type == InputReport.GetStatusResult) && (type != InputReport.ButtonsAccelerometer36IrA))
                OnUpdated();
            return true;
        }
        protected override bool ParseReport(byte[] report)
        {
            if (report[0] < 0x20)
            {
                throw new InvalidOperationException("Received an output report!");
            }
            InputReport type = (InputReport)report[0];

            if (type >= InputReport.Buttons && type <= InputReport.ButtonsAccelerometer36IrB)
            {
                if (type == InputReport.ButtonsAccelerometer36IrB)
                {
                    ReportingMode = ReportingMode.ButtonsAccelerometer36Ir;
                }
                else
                {
                    ReportingMode = (ReportingMode)type;
                }

                IRMode irMode = GetIrMode(type);
                if (this._IrMode != irMode)
                {
                    for (int i = 0; i < _CachedIRBeacons.Length; i++)
                    {
                        BasicIRBeacon newBeacon = null;
                        switch (irMode)
                        {
                        case IRMode.Basic:
                            newBeacon = new BasicIRBeacon();
                            break;

                        case IRMode.Extended:
                            newBeacon = new ExtendedIRBeacon();
                            break;

                        case IRMode.Full:
                            newBeacon = new FullIRBeacon();
                            break;
                        }
                        _CachedIRBeacons[i] = newBeacon;
                        _IRBeacons[i]       = null;
                    }
                    this._IrMode = irMode;
                }
            }
            switch (type)
            {
            case InputReport.Buttons:
                ParseButtons(report, 1);
                break;

            case InputReport.ButtonsAccelerometer:
                ParseButtons(report, 1);
                ParseAccelerometer(report, 3);
                break;

            case InputReport.Buttons8Extension:
                ParseButtons(report, 1);
                ParseExtension(report, 3, 8);
                break;

            case InputReport.ButtonsAccelerometer12Ir:
            {
                ParseButtons(report, 1);
                ParseAccelerometer(report, 3);

                ExtendedIRBeacon irBeacon;

                // Parse beacon 0.
                irBeacon      = (ExtendedIRBeacon)_CachedIRBeacons[0];
                _IRBeacons[0] = ParseExtendedBeacon(report, 6, irBeacon) ? irBeacon : null;

                // Parse beacon 1.
                irBeacon      = (ExtendedIRBeacon)_CachedIRBeacons[1];
                _IRBeacons[1] = ParseExtendedBeacon(report, 9, irBeacon) ? irBeacon : null;

                // Parse beacon 2.
                irBeacon      = (ExtendedIRBeacon)_CachedIRBeacons[2];
                _IRBeacons[2] = ParseExtendedBeacon(report, 12, irBeacon) ? irBeacon : null;

                // Parse beacon 3.
                irBeacon      = (ExtendedIRBeacon)_CachedIRBeacons[3];
                _IRBeacons[3] = ParseExtendedBeacon(report, 15, irBeacon) ? irBeacon : null;
            }
            break;

            case InputReport.Buttons19Extension:
                ParseButtons(report, 1);
                ParseExtension(report, 3, 19);
                break;

            case InputReport.ButtonsAccelerometer16Extension:
                ParseButtons(report, 1);
                ParseAccelerometer(report, 3);
                ParseExtension(report, 6, 16);
                break;

            case InputReport.Buttons10Ir9Extension:
            case InputReport.ButtonsAccelerometer10Ir6Extension:
            {
                int offset = 1;
                offset += ParseButtons(report, offset);
                if (type == InputReport.ButtonsAccelerometer10Ir6Extension)
                {
                    offset += ParseAccelerometer(report, offset);
                }

                BasicIRBeacon irBeacon;

                // Parse beacon 0.
                irBeacon      = _CachedIRBeacons[0];
                _IRBeacons[0] = ParseBasicBeacon(report, offset, 0, irBeacon) ? irBeacon : null;

                // Parse beacon 1.
                irBeacon      = _CachedIRBeacons[1];
                _IRBeacons[1] = ParseBasicBeacon(report, offset, 1, irBeacon) ? irBeacon : null;

                // Parse beacon 2.
                irBeacon      = _CachedIRBeacons[2];
                _IRBeacons[2] = ParseBasicBeacon(report, offset + 5, 0, irBeacon) ? irBeacon : null;

                // Parse beacon 3.
                irBeacon      = _CachedIRBeacons[3];
                _IRBeacons[3] = ParseBasicBeacon(report, offset + 5, 1, irBeacon) ? irBeacon : null;

                offset += 10;         // Each pair of IR-beacons is 5 bytes.

                if (type == InputReport.ButtonsAccelerometer10Ir6Extension)
                {
                    ParseExtension(report, offset, 6);
                }
                else
                {
                    ParseExtension(report, offset, 9);
                }
            }
            break;

            case InputReport.Extension:
                ParseExtension(report, 1, 21);
                break;

            case InputReport.ButtonsAccelerometer36IrA:
            {
                ParseButtons(report, 1);         // since button information is complete on both the interlaced reports it needs no temporary storage

                _PartialAccelerometerX = report[3];
                _PartialAccelerometerZ = (ushort)(((report[2] & 0x60) << 1) | ((report[1] & 0x60) >> 1));

                _PartialIRBeaconOneResult = ParseFullBeacon(report, 4, (FullIRBeacon)_CachedIRBeacons[0]);
                _PartialIRBeaconTwoResult = ParseFullBeacon(report, 13, (FullIRBeacon)_CachedIRBeacons[1]);
            }
            break;

            case InputReport.ButtonsAccelerometer36IrB:
            {
                ParseButtons(report, 1);

                // Complete the _PartialAccelerometerZ field
                _PartialAccelerometerZ = (ushort)(_PartialAccelerometerZ | ((report[2] & 60) >> 3) | ((report[1] & 60) >> 5));

                // Initialize the accelerometer if it was not yet initialized (should never happen).
                if (Accelerometer == null)
                {
                    ReadCalibrationData();
                }

                // Construct the new accelerometer-values from now completed data
                Accelerometer.Raw.X = _PartialAccelerometerX;
                Accelerometer.Raw.Y = report[3];
                Accelerometer.Raw.Z = _PartialAccelerometerZ;

                UpdateCalibratedAccelerometer();

                FullIRBeacon irBeacon;

                // Commit partial irbeacon from 'a' report
                IRBeacons[0] = _PartialIRBeaconOneResult ? _CachedIRBeacons[0] : null;

                // Commit partial irbeacon from 'a' report
                IRBeacons[1] = _PartialIRBeaconTwoResult ? _CachedIRBeacons[1] : null;

                // Parse beacon 2.
                irBeacon     = (FullIRBeacon)_CachedIRBeacons[2];
                IRBeacons[2] = ParseFullBeacon(report, 4, irBeacon) ? irBeacon : null;

                // Parse beacon 3.
                irBeacon     = (FullIRBeacon)_CachedIRBeacons[3];
                IRBeacons[3] = ParseFullBeacon(report, 13, irBeacon) ? irBeacon : null;
            }
            break;

            case InputReport.GetStatusResult:
                ParseButtons(report, 1);
                ParseStatus(report);
                break;

            case InputReport.ReadDataResult:
                ParseButtons(report, 1);
                // The rest is handled by the ReadData method (waiting for the report).
                break;

            case InputReport.WriteDataResult:
                // The rest is handled by the WriteData method (waiting for the report).
                break;

            default:
                Debug.WriteLine("Unknown report type: " + type.ToString("x"));
                return(false);
            }

            if ((type >= InputReport.Buttons || type == InputReport.GetStatusResult) && (type != InputReport.ButtonsAccelerometer36IrA))
            {
                OnUpdated();
            }
            return(true);
        }
 /// <summary>
 /// http://wiibrew.org/index.php?title=Wiimote#Extended_Mode
 /// </summary>
 protected static bool ParseExtendedBeacon(byte[] buff, int offset, ExtendedIRBeacon irBeacon)
 {
     if (buff[offset + 0] == 0xff && buff[offset + 1] == 0xff && buff[offset + 2] == 0xff)
         return false;
     irBeacon.X = buff[offset + 0] | ((buff[offset + 2] >> 4) & 0x03) << 8;
     irBeacon.Y = buff[offset + 1] | ((buff[offset + 2] >> 6) & 0x03) << 8;
     irBeacon.Size = buff[offset + 2] & 0x0f;
     return true;
 }