private void OnTrackerMessage(RiftInputReport report)
        {
            const float timeUnit = (1.0f / 1000.0f);

            if (SequenceValid) {
                uint timestampDelta;

                if (report.Timestamp < LastTimestamp)
                    timestampDelta = (uint)((((int)report.Timestamp) + 0x10000) - (int)LastTimestamp);
                else
                    timestampDelta = (uint)(report.Timestamp - LastTimestamp);

                // If we missed a small number of samples, replicate the last sample.
                if ((timestampDelta > LastSampleCount) && (timestampDelta <= 254)) {
                    MessageBodyFrame sensors = new MessageBodyFrame(this);
                    sensors.TimeDelta = (timestampDelta - LastSampleCount) * timeUnit;
                    sensors.Acceleration = LastAcceleration;
                    sensors.RotationRate = LastRotationRate;
                    sensors.MagneticField = LastMagneticField;
                    sensors.Temperature = LastTemperature;

                    Sensor.OnMessage(sensors);
                }
            } else {
                LastAcceleration = new Vector3f();
                LastRotationRate = new Vector3f();
                LastMagneticField = new Vector3f();
                LastTemperature = 0;
                SequenceValid = true;
            }

            LastSampleCount = report.SampleCount;
            LastTimestamp = report.Timestamp;

            bool convertHMDToSensor = (Coordinates == CoordinateFrame.Sensor) && (HWCoordinates == CoordinateFrame.HMD);

            //if (HandlerRef.GetHandler())
            {
                MessageBodyFrame sensors = new MessageBodyFrame(this);
                Byte iterations = report.SampleCount;

                if (report.SampleCount > 3) {
                    iterations = 3;
                    sensors.TimeDelta = (report.SampleCount - 2) * timeUnit;
                } else {
                    sensors.TimeDelta = timeUnit;
                }

                for (Byte i = 0; i < iterations; i++) {
                    sensors.Acceleration = AccelFromBodyFrameUpdate(report, i, convertHMDToSensor);
                    sensors.RotationRate = EulerFromBodyFrameUpdate(report, i, convertHMDToSensor);
                    sensors.MagneticField = MagFromBodyFrameUpdate(report, convertHMDToSensor);
                    sensors.Temperature = report.Temperature * 0.01f;
                    Sensor.OnMessage(sensors);
                    // TimeDelta for the last two sample is always fixed.
                    sensors.TimeDelta = timeUnit;
                }

                LastAcceleration = sensors.Acceleration;
                LastRotationRate = sensors.RotationRate;
                LastMagneticField = sensors.MagneticField;
                LastTemperature = sensors.Temperature;
            }
            //else
            //{
            //    UByte i = (report.SampleCount > 3) ? 2 : (report.SampleCount - 1);
            //    LastAcceleration  = AccelFromBodyFrameUpdate(report, i, convertHMDToSensor);
            //    LastRotationRate  = EulerFromBodyFrameUpdate(report, i, convertHMDToSensor);
            //    LastMagneticField = MagFromBodyFrameUpdate(report, convertHMDToSensor);
            //    LastTemperature   = report.Temperature * 0.01f;
            //}
        }
        Vector3f EulerFromBodyFrameUpdate(RiftInputReport update, Byte sampleNumber, bool convertHMDToSensor = false)
        {
            TrackerSample sample = update.Samples[sampleNumber];
            float                gx = (float)sample.Gyro.X;
            float                gy = (float)sample.Gyro.Y;
            float                gz = (float)sample.Gyro.Z;

            Vector3f val = convertHMDToSensor ? new Vector3f(gx, gz, -gy) : new Vector3f(gx, gy, gz);
            return val * 0.0001f;
        }
        Vector3f MagFromBodyFrameUpdate(RiftInputReport update, bool convertHMDToSensor = false)
        {
            // Note: Y and Z are swapped in comparison to the Accel.
            // This accounts for DK1 sensor firmware axis swap, which should be undone in future releases.
            if (!convertHMDToSensor)
            {
                return new Vector3f( (float)update.MagX,
                                    (float)update.MagZ,
                                    (float)update.MagY) * 0.0001f;
            }

            return new Vector3f((float)update.MagX,
                                (float)update.MagY,
                            -(float)update.MagZ) * 0.0001f;
        }
        // Sensor reports data in the following coordinate system:
        // Accelerometer: 10^-4 m/s^2; X forward, Y right, Z Down.
        // Gyro:          10^-4 rad/s; X positive roll right, Y positive pitch up; Z positive yaw right.
        // We need to convert it to the following RHS coordinate system:
        // X right, Y Up, Z Back (out of screen)
        //
        Vector3f AccelFromBodyFrameUpdate(RiftInputReport update, Byte sampleNumber, bool convertHMDToSensor = false)
        {
            TrackerSample sample = update.Samples[sampleNumber];
            float                ax = (float)sample.Accel.X;
            float                ay = (float)sample.Accel.Y;
            float                az = (float)sample.Accel.Z;

            Vector3f val = convertHMDToSensor ? new Vector3f(ax, az, -ay) : new Vector3f(ax, ay, az);
            return val * 0.0001f;
        }