/// <summary> /// If new data is available, updates <see cref="LatestPose"/>. /// </summary> /// <remarks> /// If the client "connection" was interrupted, this call will automatically attempt to reconnect. If /// something goes wrong during that process, it's possible that the call could throw an exception. /// </remarks> /// <returns>True if new data was available, false otherwise.</returns> public bool UpdatePose() { if (m_bPendingReconnect) { // Note: This call could throw. if (InternalConnect()) { // Successfully reconnected; clear the flag and continue normally. m_bPendingReconnect = false; } else { // Failed to reconnect; don't go any further, but try to reconnect again next time. return(false); } } NPResult getDataResult = m_clientLib.NP_GetData(ref m_trackirData, 0, 0); if (getDataResult == NPResult.OK) { if (m_trackirData.FrameSignature != m_latestFrameSignature) { // We got fresh data, so update the latest cached/transformed pose. const float kEncodedRangeMinMax = 16383.0f; const float kDecodedTranslationMinMaxMeters = 0.5f; // +/- 50 cm const float kDecodedRotationMinMaxRadians = (float)Math.PI; // +/- 180 deg // Negate right-hand rule rotations to be consistent with left-handed coordinate basis. // See remarks in the comments for the TrackIRData struct for more information. float rollRad = (-m_trackirData.Roll / kEncodedRangeMinMax) * kDecodedRotationMinMaxRadians; float pitchRad = (-m_trackirData.Pitch / kEncodedRangeMinMax) * kDecodedRotationMinMaxRadians; float yawRad = (-m_trackirData.Yaw / kEncodedRangeMinMax) * kDecodedRotationMinMaxRadians; float xMeters = (m_trackirData.X / kEncodedRangeMinMax) * kDecodedTranslationMinMaxMeters; float yMeters = (m_trackirData.Y / kEncodedRangeMinMax) * kDecodedTranslationMinMaxMeters; float zMeters = (m_trackirData.Z / kEncodedRangeMinMax) * kDecodedTranslationMinMaxMeters; m_latestPose.Orientation = Pose.Quaternion.FromTaitBryanIntrinsicZYX(rollRad, yawRad, pitchRad); m_latestPose.PositionMeters = new Pose.Vector3(xMeters, yMeters, zMeters); m_latestFrameSignature = m_trackirData.FrameSignature; // Successfully retrieved a new pose. return(true); } else { // No error, but no new data available. return(false); } } else { // Got an unexpected return code from the NP_GetData call. m_latestFrameSignature = -1; m_bPendingReconnect = true; return(false); } }
/// <summary> /// Stops data transmission and unregisters the application's window handle. /// </summary> public void Disconnect() { if (m_bDataTransmitting) { NPResult stopDataResult = m_clientLib.NP_StopDataTransmission(); if (stopDataResult != NPResult.OK) { Console.WriteLine("WARNING: NP_StopDataTransmission returned " + stopDataResult.ToString() + "."); } m_bDataTransmitting = false; } if (m_bRegisteredWindowHandle) { NPResult unregisterResult = m_clientLib.NP_UnregisterWindowHandle(); if (unregisterResult != NPResult.OK) { Console.WriteLine("WARNING: NP_UnregisterWindowHandle returned " + unregisterResult.ToString() + "."); } m_bRegisteredWindowHandle = false; } }
/// <summary> /// Uses the cached appId and hwnd to initialize the TrackIR API. /// </summary> /// <returns> /// True if initialization completed successfully, false if the API returned the code /// <see cref="NPResult.ERR_DEVICE_NOT_PRESENT"/>. Any other failure condition throws an exception. /// </returns> private bool InternalConnect() { // Clear this flag. Most exit paths from this function represent errors we can't recover from, and we // shouldn't keep trying repeatedly; the only exception is waiting for ERR_DEVICE_NOT_PRESENT to resolve. m_bPendingReconnect = false; // Retrieve host software version. UInt16 version; NPResult queryVersionResult = m_clientLib.NP_QueryVersion(out version); if (queryVersionResult == NPResult.ERR_DEVICE_NOT_PRESENT) { // Don't go any further; we'll try to connect again next time UpdatePose is called. m_bPendingReconnect = true; return(false); } else if (queryVersionResult != NPResult.OK) { Console.WriteLine("WARNING: NP_QueryVersion returned " + queryVersionResult.ToString() + "."); } HostSoftwareVersionMajor = (version >> 8); HostSoftwareVersionMinor = (version & 0x00FF); // Retrieve signature object and validate that signature strings match expected values. TrackIRSignature signature = new TrackIRSignature(); NPResult getSignatureResult = m_clientLib.NP_GetSignature(ref signature); if (getSignatureResult != NPResult.OK) { throw new TrackIRException("NP_GetSignature returned " + getSignatureResult.ToString() + "."); } const string kExpectedAppSignature = "hardware camera\n software processing data\n track user movement\n\n Copyright EyeControl Technologies"; const string kExpectedDllSignature = "precise head tracking\n put your head into the game\n now go look around\n\n Copyright EyeControl Technologies"; if (signature.AppSignature != kExpectedAppSignature || signature.DllSignature != kExpectedDllSignature) { throw new TrackIRException("Unable to verify TrackIR Enhanced signature values."); } // Register the application window for liveness checks. This allows the TrackIR software to // detect situations where e.g. your application crashes and fails to shut down cleanly. NPResult registerHwndResult = m_clientLib.NP_RegisterWindowHandle(m_appHwnd); if (registerHwndResult == NPResult.OK) { m_bRegisteredWindowHandle = true; } else { throw new TrackIRException("NP_RegisterWindowHandle returned " + registerHwndResult.ToString() + "."); } // Register the application by its NaturalPoint-assigned ID. NPResult registerIdResult = m_clientLib.NP_RegisterProgramProfileID(m_appId); if (registerIdResult != NPResult.OK) { throw new TrackIRException("NP_RegisterProgramProfileID returned " + registerIdResult.ToString() + "."); } // Signal that we want to start receiving tracking data. NPResult startDataResult = m_clientLib.NP_StartDataTransmission(); if (startDataResult == NPResult.OK) { m_bDataTransmitting = true; } else { throw new TrackIRException("NP_StartDataTransmission returned " + startDataResult.ToString() + "."); } return(true); }