diff --git a/.clang-format b/.clang-format index 989c047e..6c82431c 100644 --- a/.clang-format +++ b/.clang-format @@ -1,2 +1,7 @@ BasedOnStyle: Google -ColumnLimit: 170 \ No newline at end of file +ColumnLimit: 150 +BinPackParameters: false +BinPackArguments: false +AlignAfterOpenBracket: AlwaysBreak +AllowShortFunctionsOnASingleLine: Empty +NamespaceIndentation: All \ No newline at end of file diff --git a/README.md b/README.md index 1b2fc51e..a4a09028 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ If you are planning on modifying source files, refer to [BUILDING.md](https://gi ## Compatibility ### Compatible Hardware -* [LucidVR Gloves](https://github.com/LucidVR/lucidgloves-hardware) - Lucas VRTech +* [LucidGloves](https://github.com/LucidVR/lucidgloves) - Lucas VRTech * [Fngrs](https://github.com/danwillm/Fngrs/) - danwillm * Have your own hardware you want to feature here? Let us know! diff --git a/include/Bones.h b/include/Bones.h index 3d923cae..a898c475 100644 --- a/include/Bones.h +++ b/include/Bones.h @@ -6,78 +6,79 @@ #include "openvr_driver.h" enum class HandSkeletonBone : vr::BoneIndex_t { - eBone_Root = 0, - eBone_Wrist, - eBone_Thumb0, - eBone_Thumb1, - eBone_Thumb2, - eBone_Thumb3, - eBone_IndexFinger0, - eBone_IndexFinger1, - eBone_IndexFinger2, - eBone_IndexFinger3, - eBone_IndexFinger4, - eBone_MiddleFinger0, - eBone_MiddleFinger1, - eBone_MiddleFinger2, - eBone_MiddleFinger3, - eBone_MiddleFinger4, - eBone_RingFinger0, - eBone_RingFinger1, - eBone_RingFinger2, - eBone_RingFinger3, - eBone_RingFinger4, - eBone_PinkyFinger0, - eBone_PinkyFinger1, - eBone_PinkyFinger2, - eBone_PinkyFinger3, - eBone_PinkyFinger4, - eBone_Aux_Thumb, - eBone_Aux_IndexFinger, - eBone_Aux_MiddleFinger, - eBone_Aux_RingFinger, - eBone_Aux_PinkyFinger, - eBone_Count + Root = 0, + Wrist, + Thumb0, + Thumb1, + Thumb2, + Thumb3, + IndexFinger0, + IndexFinger1, + IndexFinger2, + IndexFinger3, + IndexFinger4, + MiddleFinger0, + MiddleFinger1, + MiddleFinger2, + MiddleFinger3, + MiddleFinger4, + RingFinger0, + RingFinger1, + RingFinger2, + RingFinger3, + RingFinger4, + PinkyFinger0, + PinkyFinger1, + PinkyFinger2, + PinkyFinger3, + PinkyFinger4, + AuxThumb, + AuxIndexFinger, + AuxMiddleFinger, + AuxRingFinger, + AuxPinkyFinger, + _Count }; -const short NUM_BONES = (short)HandSkeletonBone::eBone_Count; +const short NUM_BONES = static_cast(HandSkeletonBone::_Count); extern vr::VRBoneTransform_t rightOpenPose[NUM_BONES]; extern vr::VRBoneTransform_t leftOpenPose[NUM_BONES]; -struct Transform_t { - Transform_t(); +struct Transform { + Transform(); std::array rotation; std::array translation; }; -struct AnimationData_t { - AnimationData_t(); - Transform_t startTransform; +struct AnimationData { + AnimationData(); + Transform startTransform; float startTime; - Transform_t endTransform; + Transform endTransform; float endTime; + float fScaled; }; class IModelManager { public: virtual bool Load() = 0; - virtual AnimationData_t GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, float f) const = 0; - virtual Transform_t GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const = 0; + virtual AnimationData GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, float f) const = 0; + virtual Transform GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const = 0; }; class BoneAnimator { public: - BoneAnimator(const std::string& fileName); + explicit BoneAnimator(const std::string& fileName); void ComputeSkeletonTransforms(vr::VRBoneTransform_t* skeleton, const std::array& flexion, const bool rightHand); - void TransformLeftBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex); + static void TransformLeftBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex); private: - vr::VRBoneTransform_t GetTransformForBone(const HandSkeletonBone& boneIndex, const float f, const bool rightHand); + void SetTransformForBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex, const float f, const bool rightHand) const; - std::string m_fileName; - std::unique_ptr m_modelManager; - bool m_loaded; - std::vector m_keyframes; + std::string fileName_; + std::unique_ptr modelManager_; + bool loaded_; + std::vector keyframes_; }; \ No newline at end of file diff --git a/include/Calibration.h b/include/Calibration.h index 081f361e..ed0fe8b7 100644 --- a/include/Calibration.h +++ b/include/Calibration.h @@ -1,23 +1,31 @@ #pragma once -#include -#include + #include "DeviceConfiguration.h" +#include "openvr_driver.h" + +enum class CalibrationMethod { + Hardware, + Ui, + None, +}; class Calibration { -public: - Calibration(); + public: + Calibration(); + + void StartCalibration(vr::DriverPose_t maintainPose, CalibrationMethod method); - void StartCalibration(vr::DriverPose_t maintainPose); + VRPoseConfiguration CompleteCalibration( + vr::TrackedDevicePose_t controllerPose, VRPoseConfiguration poseConfiguration, bool isRightHand, CalibrationMethod method); - VRPoseConfiguration_t CompleteCalibration(vr::TrackedDevicePose_t controllerPose, VRPoseConfiguration_t poseConfiguration, bool isRightHand); + void CancelCalibration(CalibrationMethod method); - void CancelCalibration(); + bool IsCalibrating() const; - bool isCalibrating(); - - vr::DriverPose_t GetMaintainPose(); + vr::DriverPose_t GetMaintainPose() const; -private: - vr::DriverPose_t m_maintainPose; - bool m_isCalibrating; + private: + vr::DriverPose_t maintainPose_; + bool isCalibrating_; + CalibrationMethod calibratingMethod_; }; \ No newline at end of file diff --git a/include/Communication/BTSerialCommunicationManager.h b/include/Communication/BTSerialCommunicationManager.h index bfde2704..9abc909d 100644 --- a/include/Communication/BTSerialCommunicationManager.h +++ b/include/Communication/BTSerialCommunicationManager.h @@ -1,61 +1,39 @@ #pragma once -#include -#include + +#include #include -#include #include -#include #include -#include -#include -#include -#include +#include -#include "CommunicationManager.h" +#include "Communication/CommunicationManager.h" #include "DeviceConfiguration.h" -#include "DriverLog.h" +#include "Encode/EncodingManager.h" -class BTSerialCommunicationManager : public ICommunicationManager { +class BTSerialCommunicationManager : public CommunicationManager { public: - BTSerialCommunicationManager(const VRBTSerialConfiguration_t& configuration, std::unique_ptr encodingManager); + BTSerialCommunicationManager( + std::unique_ptr encodingManager, VRBTSerialConfiguration configuration, const VRDeviceConfiguration& deviceConfiguration); - // start a thread that listens for updates from the device and calls the callback with data - void BeginListener(const std::function& callback); - // returns if connected or not - bool IsConnected(); - // close the serial port - void Disconnect(); + bool IsConnected() override; - void QueueSend(const VRFFBData_t& data); + protected: + bool Connect() override; + bool DisconnectFromDevice() override; + void LogError(const char* message) override; + void LogMessage(const char* message) override; + bool ReceiveNextPacket(std::string& buff) override; + bool SendMessageToDevice() override; private: - bool Connect(); - void ListenerThread(const std::function& callback); - bool ReceiveNextPacket(std::string& buff); - bool GetPairedDeviceBtAddress(); + bool ConnectToDevice(const BTH_ADDR& deviceBtAddress); + bool GetPairedDeviceBtAddress(BTH_ADDR* deviceBtAddress); bool StartupWindowsSocket(); - bool ConnectToDevice(); - bool SendMessageToDevice(); - void WaitAttemptConnection(); - bool DisconnectFromDevice(); - void LogError(const char* message); - void LogMessage(const char* message); - - std::atomic m_isConnected; - std::atomic m_threadActive; - std::thread m_serialThread; - - std::unique_ptr m_encodingManager; - - VRBTSerialConfiguration_t m_btSerialConfiguration; - BTH_ADDR m_deviceBtAddress; - SOCKADDR_BTH m_btSocketAddress; - SOCKET m_btClientSocket; - WCHAR* m_wcDeviceName; + VRBTSerialConfiguration btSerialConfiguration_; - std::mutex m_writeMutex; + std::atomic isConnected_; - std::string m_writeString = "\n"; + std::atomic btClientSocket_; }; \ No newline at end of file diff --git a/include/Communication/CommunicationManager.h b/include/Communication/CommunicationManager.h index f24ff741..fc28901b 100644 --- a/include/Communication/CommunicationManager.h +++ b/include/Communication/CommunicationManager.h @@ -1,17 +1,43 @@ #pragma once + +#include #include #include +#include +#include +#include +#include "DeviceConfiguration.h" #include "Encode/EncodingManager.h" -class ICommunicationManager { +class CommunicationManager { public: - virtual void BeginListener(const std::function& callback) = 0; + explicit CommunicationManager(const VRDeviceConfiguration& deviceConfiguration); + CommunicationManager(std::unique_ptr encodingManager, const VRDeviceConfiguration& deviceConfiguration); + + virtual void BeginListener(const std::function& callback); + virtual void Disconnect(); + virtual void QueueSend(const VRFFBData& data); + virtual bool IsConnected() = 0; - virtual void Disconnect() = 0; - virtual void QueueSend(const VRFFBData_t& data) = 0; + protected: + virtual void ListenerThread(const std::function& callback); + virtual void WaitAttemptConnection(); + + virtual bool Connect() = 0; + virtual bool DisconnectFromDevice() = 0; + virtual void LogError(const char* message) = 0; + virtual void LogMessage(const char* message) = 0; + virtual bool ReceiveNextPacket(std::string& buff) = 0; + virtual bool SendMessageToDevice() = 0; + + std::unique_ptr encodingManager_; + VRDeviceConfiguration deviceConfiguration_; + + std::atomic threadActive_; + std::thread thread_; - private: - std::unique_ptr m_encodingManager; + std::mutex writeMutex_; + std::string writeString_; }; \ No newline at end of file diff --git a/include/Communication/NamedPipeCommunicationManager.h b/include/Communication/NamedPipeCommunicationManager.h new file mode 100644 index 00000000..1f29a6f7 --- /dev/null +++ b/include/Communication/NamedPipeCommunicationManager.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include "Communication/CommunicationManager.h" +#include "DeviceConfiguration.h" +#include "Util/NamedPipeListener.h" + +class NamedPipeCommunicationManager : public CommunicationManager { + public: + NamedPipeCommunicationManager(VRNamedPipeInputConfiguration configuration, const VRDeviceConfiguration& deviceConfiguration); + bool IsConnected() override; + void QueueSend(const VRFFBData& data) override{}; + + protected: + bool Connect() override; + bool DisconnectFromDevice() override; + void LogError(const char* message) override; + void LogMessage(const char* message) override; + + // Functions currently unimplemented + bool SendMessageToDevice() override { + return true; + }; + bool ReceiveNextPacket(std::string& buff) override { + return true; + }; + + void BeginListener(const std::function& callback) override; + + private: + std::unique_ptr> namedPipeListener_; + std::atomic isConnected_; + + std::function callback_; + + VRNamedPipeInputConfiguration configuration_; +}; \ No newline at end of file diff --git a/include/Communication/SerialCommunicationManager.h b/include/Communication/SerialCommunicationManager.h index 29d10556..a07a5f5c 100644 --- a/include/Communication/SerialCommunicationManager.h +++ b/include/Communication/SerialCommunicationManager.h @@ -1,64 +1,36 @@ #pragma once -#include +#include #include -#include #include -#include -#include +#include -#include "CommunicationManager.h" +#include "Communication/CommunicationManager.h" #include "DeviceConfiguration.h" +#include "Encode/EncodingManager.h" -class SerialCommunicationManager : public ICommunicationManager { +class SerialCommunicationManager : public CommunicationManager { public: - SerialCommunicationManager(const VRSerialConfiguration_t& configuration, std::unique_ptr encodingManager) - : m_serialConfiguration(configuration), - m_encodingManager(std::move(encodingManager)), - m_isConnected(false), - m_hSerial(0), - m_errors(0) - { - //initially no force feedback - VRFFBData_t data(0, 0, 0, 0, 0); + SerialCommunicationManager( + std::unique_ptr encodingManager, VRSerialConfiguration configuration, const VRDeviceConfiguration& deviceConfiguration); - m_writeString = m_encodingManager->Encode(data); - }; + bool IsConnected() override; - void BeginListener(const std::function& callback); - bool IsConnected(); - void Disconnect(); - - void QueueSend(const VRFFBData_t& data); + protected: + bool Connect() override; + bool DisconnectFromDevice() override; + void LogError(const char* message) override; + void LogMessage(const char* message) override; + bool ReceiveNextPacket(std::string& buff) override; + bool SendMessageToDevice() override; private: - bool Connect(); - void ListenerThread(const std::function& callback); - bool ReceiveNextPacket(std::string& buff); - bool PurgeBuffer(); - bool Write(); - void WaitAttemptConnection(); - bool DisconnectFromDevice(); - - void LogMessage(const char* message); - void LogError(const char* message); - - bool m_isConnected; - // Serial comm handler - HANDLE m_hSerial; - // Connection information - COMSTAT m_status; - // Error tracking - DWORD m_errors; - std::atomic m_threadActive; - std::thread m_serialThread; - - VRSerialConfiguration_t m_serialConfiguration; + bool PurgeBuffer() const; - std::unique_ptr m_encodingManager; + VRSerialConfiguration serialConfiguration_; - std::mutex m_writeMutex; + std::atomic isConnected_; - std::string m_writeString; + std::atomic hSerial_; }; \ No newline at end of file diff --git a/include/ControllerDiscovery.h b/include/ControllerDiscovery.h index 063286d6..0486d1bb 100644 --- a/include/ControllerDiscovery.h +++ b/include/ControllerDiscovery.h @@ -1,23 +1,24 @@ #pragma once -#include #include +#include + +#include "Util/NamedPipeListener.h" #include "openvr_driver.h" -#include "Util/NamedPipe.h" -struct ControllerDiscoveryPipeData_t { +struct ControllerDiscoveryPipeData { short controllerId; }; class ControllerDiscovery { public: - ControllerDiscovery(vr::ETrackedControllerRole role, std::function callback); + ControllerDiscovery(vr::ETrackedControllerRole role, std::function callback); void Start(); - void Stop(); + void Stop() const; private: - vr::ETrackedControllerRole m_role; - std::unique_ptr m_pipe; - std::function m_callback; + vr::ETrackedControllerRole role_; + std::unique_ptr> pipe_; + std::function callback_; }; \ No newline at end of file diff --git a/include/ControllerPose.h b/include/ControllerPose.h index 044177c8..23f067c1 100644 --- a/include/ControllerPose.h +++ b/include/ControllerPose.h @@ -1,41 +1,46 @@ #pragma once #include + #include -#include "DeviceConfiguration.h" -#include "ControllerDiscovery.h" #include "Calibration.h" -#include "Util/NamedPipe.h" +#include "ControllerDiscovery.h" +#include "DeviceConfiguration.h" +#include "Util/NamedPipeListener.h" + +struct CalibrationDataIn { + uint8_t start; +}; class ControllerPose { public: - ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, std::string thisDeviceManufacturer, - VRPoseConfiguration_t poseConfiguration); + ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, std::string thisDeviceManufacturer, VRPoseConfiguration poseConfiguration); + ~ControllerPose(); - vr::DriverPose_t UpdatePose(); + vr::DriverPose_t UpdatePose() const; - void StartCalibration(); + void StartCalibration(CalibrationMethod method) const; - void CompleteCalibration(); + void CompleteCalibration(CalibrationMethod method); - void CancelCalibration(); + void CancelCalibration(CalibrationMethod method) const; - bool isCalibrating(); + bool IsCalibrating() const; private: - uint32_t m_shadowControllerId = vr::k_unTrackedDeviceIndexInvalid; + uint32_t shadowControllerId_ = vr::k_unTrackedDeviceIndexInvalid; - VRPoseConfiguration_t m_poseConfiguration; + VRPoseConfiguration poseConfiguration_; - vr::ETrackedControllerRole m_shadowDeviceOfRole = vr::TrackedControllerRole_Invalid; + vr::ETrackedControllerRole shadowDeviceOfRole_ = vr::TrackedControllerRole_Invalid; - std::string m_thisDeviceManufacturer; + std::string thisDeviceManufacturer_; - vr::TrackedDevicePose_t GetControllerPose(); + vr::TrackedDevicePose_t GetControllerPose() const; - bool isRightHand(); + bool IsRightHand() const; - std::unique_ptr m_controllerDiscoverer; - std::unique_ptr m_calibrationPipe; - std::unique_ptr m_calibration; + std::unique_ptr controllerDiscoverer_; + std::unique_ptr> calibrationPipe_; + std::unique_ptr calibration_; }; \ No newline at end of file diff --git a/include/DeviceConfiguration.h b/include/DeviceConfiguration.h index c9b70e4a..1051c7bc 100644 --- a/include/DeviceConfiguration.h +++ b/include/DeviceConfiguration.h @@ -1,10 +1,8 @@ #pragma once -#include "openvr_driver.h" +#include -#include "Communication/CommunicationManager.h" -#include "DeviceDriver/DeviceDriver.h" -#include "Encode/EncodingManager.h" +#include "openvr_driver.h" extern const char* c_poseSettingsSection; extern const char* c_driverSettingsSection; @@ -12,70 +10,91 @@ extern const char* c_serialCommunicationSettingsSection; extern const char* c_btserialCommunicationSettingsSection; extern const char* c_knuckleDeviceSettingsSection; extern const char* c_lucidGloveDeviceSettingsSection; +extern const char* c_alphaEncodingSettingsSection; +extern const char* c_legacyEncodingSettingsSection; + +extern const char* c_deviceDriverManufacturer; enum class VRCommunicationProtocol { - SERIAL = 0, - BTSERIAL = 1, + Serial, + BtSerial, + NamedPipe, }; enum class VREncodingProtocol { - LEGACY = 0, - ALPHA = 1, + Legacy = 0, + Alpha = 1, }; enum class VRDeviceDriver { - LUCIDGLOVES = 0, - EMULATED_KNUCKLES = 1, + LucidGloves = 0, + EmulatedKnuckles = 1, +}; + +struct VRSerialConfiguration { + std::string port; + int baudRate; + + VRSerialConfiguration(std::string port, const int baudRate) : port(std::move(port)), baudRate(baudRate) {} }; -struct VRSerialConfiguration_t { - std::string port; - int baudRate; +struct VRBTSerialConfiguration { + std::string name; - VRSerialConfiguration_t(std::string port, int baudRate) : port(port), baudRate(baudRate) {}; + explicit VRBTSerialConfiguration(std::string name) : name(std::move(name)) {} }; -struct VRBTSerialConfiguration_t { - std::string name; +struct VRNamedPipeInputConfiguration { + std::string pipeName; - VRBTSerialConfiguration_t(std::string name) : name(name) {}; + VRNamedPipeInputConfiguration(std::string pipeName) : pipeName(std::move(pipeName)) {} }; -struct VRPoseConfiguration_t { - VRPoseConfiguration_t(vr::HmdVector3_t offsetVector, vr::HmdQuaternion_t angleOffsetQuaternion, float poseTimeOffset, - bool controllerOverrideEnabled, int controllerIdOverride) : - offsetVector(offsetVector), - angleOffsetQuaternion(angleOffsetQuaternion), - poseTimeOffset(poseTimeOffset), - controllerOverrideEnabled(controllerOverrideEnabled), - controllerIdOverride(controllerIdOverride) {}; - vr::HmdVector3_t offsetVector; - vr::HmdQuaternion_t angleOffsetQuaternion; - float poseTimeOffset; - int controllerIdOverride; - bool controllerOverrideEnabled; +struct VRPoseConfiguration { + vr::HmdVector3_t offsetVector; + vr::HmdQuaternion_t angleOffsetQuaternion; + float poseTimeOffset; + int controllerIdOverride; + bool controllerOverrideEnabled; + bool calibrationButtonEnabled; + + VRPoseConfiguration( + const vr::HmdVector3_t offsetVector, + const vr::HmdQuaternion_t angleOffsetQuaternion, + const float poseTimeOffset, + const bool controllerOverrideEnabled, + const int controllerIdOverride, + const bool calibrationButtonEnabled) + : offsetVector(offsetVector), + angleOffsetQuaternion(angleOffsetQuaternion), + poseTimeOffset(poseTimeOffset), + controllerIdOverride(controllerIdOverride), + controllerOverrideEnabled(controllerOverrideEnabled), + calibrationButtonEnabled(calibrationButtonEnabled) {} }; -struct VRDeviceConfiguration_t { - VRDeviceConfiguration_t(vr::ETrackedControllerRole role, - bool enabled, - VRPoseConfiguration_t poseConfiguration, - VREncodingProtocol encodingProtocol, - VRCommunicationProtocol communicationProtocol, - VRDeviceDriver deviceDriver) : - role(role), - enabled(enabled), - poseConfiguration(poseConfiguration), - encodingProtocol(encodingProtocol), - communicationProtocol(communicationProtocol), - deviceDriver(deviceDriver) {}; - - vr::ETrackedControllerRole role; - bool enabled; - - VRPoseConfiguration_t poseConfiguration; - - VREncodingProtocol encodingProtocol; - VRCommunicationProtocol communicationProtocol; - VRDeviceDriver deviceDriver; +struct VRDeviceConfiguration { + vr::ETrackedControllerRole role; + bool enabled; + bool feedbackEnabled; + VRPoseConfiguration poseConfiguration; + VREncodingProtocol encodingProtocol; + VRCommunicationProtocol communicationProtocol; + VRDeviceDriver deviceDriver; + + VRDeviceConfiguration( + const vr::ETrackedControllerRole role, + const bool enabled, + const bool feedbackEnabled, + const VRPoseConfiguration poseConfiguration, + const VREncodingProtocol encodingProtocol, + const VRCommunicationProtocol communicationProtocol, + const VRDeviceDriver deviceDriver) + : role(role), + enabled(enabled), + feedbackEnabled(feedbackEnabled), + poseConfiguration(poseConfiguration), + encodingProtocol(encodingProtocol), + communicationProtocol(communicationProtocol), + deviceDriver(deviceDriver) {} }; diff --git a/include/DeviceDriver/DeviceDriver.h b/include/DeviceDriver/DeviceDriver.h index 95e14cf7..02416f17 100644 --- a/include/DeviceDriver/DeviceDriver.h +++ b/include/DeviceDriver/DeviceDriver.h @@ -1,52 +1,50 @@ #pragma once -#include "openvr_driver.h" + +#include +#include + +#include "Bones.h" +#include "Communication/CommunicationManager.h" +#include "ControllerPose.h" #include "DeviceConfiguration.h" +#include "openvr_driver.h" -class IDeviceDriver : public vr::ITrackedDeviceServerDriver { -public: - /** - Initialize your controller here. Give OpenVR information - about your controller and set up handles to inform OpenVR when - the controller state changes. - **/ - virtual vr::EVRInitError Activate(uint32_t unObjectId) = 0; - - /** - Un-initialize your controller here. - **/ - virtual void Deactivate() = 0; - - /** - Tell your hardware to go into stand-by mode (low-power). - **/ - virtual void EnterStandby() = 0; - - /** - Take a look at the comment block for this method on ITrackedDeviceServerDriver. So as far - as I understand, driver classes like this one can implement lots of functionality that - can be categorized into components. This class just acts as an input device, so it will - return the IVRDriverInput class, but it could return other component classes if it had - more functionality, such as maybe overlays or UI functionality. - **/ - virtual void* GetComponent(const char* pchComponentNameAndVersion) = 0; - - /** - Refer to ITrackedDeviceServerDriver. I think it sums up what this does well. - **/ - virtual void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) = 0; - - /** - Returns the Pose for your device. Pose is an object that contains the position, rotation, velocity, - and angular velocity of your device. - **/ - virtual vr::DriverPose_t GetPose() = 0; - - /** - You can retrieve the state of your device here and update OpenVR if anything has changed. This - method should be called every frame. - **/ - virtual void RunFrame() = 0; - - virtual std::string GetSerialNumber() = 0; - virtual bool IsActive() = 0; +class DeviceDriver : public vr::ITrackedDeviceServerDriver { + public: + DeviceDriver( + std::unique_ptr communicationManager, + std::shared_ptr boneAnimator, + std::string serialNumber, + VRDeviceConfiguration configuration); + + vr::EVRInitError Activate(uint32_t unObjectId) override; + void Deactivate() override; + void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) override; + void EnterStandby() override; + void* GetComponent(const char* pchComponentNameAndVersion) override; + vr::DriverPose_t GetPose() override; + virtual std::string GetSerialNumber(); + virtual bool IsActive(); + virtual void RunFrame(); + + protected: + virtual bool IsRightHand() const; + virtual void StartDevice(); + + virtual void HandleInput(VRInputData data) = 0; + virtual void SetupProps(vr::PropertyContainerHandle_t& props) = 0; + virtual void StartingDevice() = 0; + virtual void StoppingDevice() = 0; + + std::unique_ptr communicationManager_; + std::shared_ptr boneAnimator_; + VRDeviceConfiguration configuration_; + std::string serialNumber_; + + std::unique_ptr controllerPose_; + vr::VRInputComponentHandle_t skeletalComponentHandle_; + vr::VRBoneTransform_t handTransforms_[NUM_BONES]; + + bool hasActivated_; + uint32_t driverId_; }; \ No newline at end of file diff --git a/include/DeviceDriver/KnuckleDriver.h b/include/DeviceDriver/KnuckleDriver.h index 27d3edc8..be9cc11e 100644 --- a/include/DeviceDriver/KnuckleDriver.h +++ b/include/DeviceDriver/KnuckleDriver.h @@ -1,53 +1,59 @@ #pragma once -#include "openvr_driver.h" - -#include #include #include "Bones.h" #include "Communication/CommunicationManager.h" -#include "ControllerPose.h" #include "DeviceConfiguration.h" #include "DeviceDriver/DeviceDriver.h" -#include "Encode/LegacyEncodingManager.h" +#include "Encode/EncodingManager.h" #include "ForceFeedback.h" +#include "openvr_driver.h" -class KnuckleDeviceDriver : public IDeviceDriver { - public: - KnuckleDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, std::string serialNumber, std::shared_ptr boneAnimator); - - vr::EVRInitError Activate(uint32_t unObjectId); - void Deactivate(); - - void EnterStandby(); - void* GetComponent(const char* pchComponentNameAndVersion); - void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize); - vr::DriverPose_t GetPose(); - void RunFrame(); +enum class KnuckleDeviceComponentIndex : int { + SystemClick = 0, + SystemTouch, + TriggerClick, + TriggerValue, + TrackpadX, + TrackpadY, + TrackpadTouch, + TrackpadForce, + GripTouch, + GripForce, + GripValue, + ThumbstickClick, + ThumbstickTouch, + ThumbstickX, + ThumbstickY, + AClick, + ATouch, + BClick, + BTouch, + FingerIndex, + FingerMiddle, + FingerRing, + FingerPinky, + _Count +}; - std::string GetSerialNumber(); - bool IsActive(); +class KnuckleDeviceDriver : public DeviceDriver { + public: + KnuckleDeviceDriver( + std::unique_ptr communicationManager, + std::shared_ptr boneAnimator, + std::string serialNumber, + bool approximateThumb, + VRDeviceConfiguration configuration); + + void HandleInput(VRInputData data) override; + void SetupProps(vr::PropertyContainerHandle_t& props) override; + void StartingDevice() override; + void StoppingDevice() override; private: - void StartDevice(); - bool IsRightHand() const; - - bool m_hasActivated; - uint32_t m_driverId; - - vr::VRInputComponentHandle_t m_skeletalComponentHandle{}; - vr::VRInputComponentHandle_t m_inputComponentHandles[23]{}; - - vr::VRInputComponentHandle_t m_haptic{}; - - vr::VRBoneTransform_t m_handTransforms[NUM_BONES]; - - VRDeviceConfiguration_t m_configuration; - std::unique_ptr m_communicationManager; - std::string m_serialNumber; - - std::unique_ptr m_controllerPose; - std::unique_ptr m_ffbProvider; - std::shared_ptr m_boneAnimator; + vr::VRInputComponentHandle_t inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::_Count)]; + vr::VRInputComponentHandle_t haptic_; + std::unique_ptr ffbProvider_; + bool approximateThumb_; }; diff --git a/include/DeviceDriver/LucidGloveDriver.h b/include/DeviceDriver/LucidGloveDriver.h index 730cf027..255b56c6 100644 --- a/include/DeviceDriver/LucidGloveDriver.h +++ b/include/DeviceDriver/LucidGloveDriver.h @@ -1,50 +1,46 @@ #pragma once -#include "openvr_driver.h" -#include #include #include "Bones.h" #include "Communication/CommunicationManager.h" -#include "ControllerPose.h" #include "DeviceConfiguration.h" #include "DeviceDriver/DeviceDriver.h" -#include "Encode/LegacyEncodingManager.h" - -class LucidGloveDeviceDriver : public IDeviceDriver { - public: - LucidGloveDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, std::string serialNumber, - std::shared_ptr boneAnimator); - - vr::EVRInitError Activate(uint32_t unObjectId); - void Deactivate(); +#include "Encode/EncodingManager.h" +#include "openvr_driver.h" - void EnterStandby(); - void* GetComponent(const char* pchComponentNameAndVersion); - void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize); - vr::DriverPose_t GetPose(); - void RunFrame(); +enum class LucidGloveDeviceComponentIndex : int { + JoyX = 0, + JoyY, + JoyBtn, + BtnTrg, + BtnA, + BtnB, + GesGrab, + GesPinch, + Haptic, + TrgThumb, + TrgIndex, + TrgMiddle, + TrgRing, + TrgPinky, + BtnMenu, + _Count +}; - std::string GetSerialNumber(); +class LucidGloveDeviceDriver : public DeviceDriver { + public: + LucidGloveDeviceDriver( + std::unique_ptr communicationManager, + std::shared_ptr boneAnimator, + const std::string& serialNumber, + VRDeviceConfiguration configuration); - bool IsActive(); + void HandleInput(VRInputData data) override; + void SetupProps(vr::PropertyContainerHandle_t& props) override; + void StartingDevice() override; + void StoppingDevice() override; private: - void StartDevice(); - bool IsRightHand() const; - - bool m_hasActivated; - uint32_t m_driverId; - - vr::VRInputComponentHandle_t m_skeletalComponentHandle{}; - vr::VRInputComponentHandle_t m_inputComponentHandles[15]{}; - - vr::VRBoneTransform_t m_handTransforms[NUM_BONES]; - - VRDeviceConfiguration_t m_configuration; - std::unique_ptr m_communicationManager; - std::string m_serialNumber; - - std::unique_ptr m_controllerPose; - std::shared_ptr m_boneAnimator; + vr::VRInputComponentHandle_t inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::_Count)]; }; diff --git a/include/DeviceProvider.h b/include/DeviceProvider.h index f634b9ae..fe874559 100644 --- a/include/DeviceProvider.h +++ b/include/DeviceProvider.h @@ -3,16 +3,12 @@ #undef _WINSOCKAPI_ #define _WINSOCKAPI_ -#include "openvr_driver.h" - #include #include "Bones.h" -#include "Communication/CommunicationManager.h" #include "DeviceConfiguration.h" #include "DeviceDriver/DeviceDriver.h" -#include "DriverLog.h" -#include "Encode/EncodingManager.h" +#include "openvr_driver.h" /** This class instantiates all the device drivers you have, meaning if you've @@ -25,47 +21,47 @@ too. class DeviceProvider : public vr::IServerTrackedDeviceProvider { public: /** - Initiailze and add your drivers to OpenVR here. + Initialize and add your drivers to OpenVR here. **/ - vr::EVRInitError Init(vr::IVRDriverContext* pDriverContext); + vr::EVRInitError Init(vr::IVRDriverContext* pDriverContext) override; /** Called right before your driver is unloaded. **/ - void Cleanup(); + void Cleanup() override; /** Returns version of the openVR interface this driver works with. **/ - const char* const* GetInterfaceVersions(); + const char* const* GetInterfaceVersions() override; /** Called every frame. Update your drivers here. **/ - void RunFrame(); + void RunFrame() override; /** Return true if standby mode should be blocked. False otherwise. **/ - bool ShouldBlockStandbyMode(); + bool ShouldBlockStandbyMode() override; /** Called when OpenVR goes into stand-by mode, so you can tell your devices to go into stand-by mode **/ - void EnterStandby(); + void EnterStandby() override; /** Called when OpenVR leaves stand-by mode. **/ - void LeaveStandby(); + void LeaveStandby() override; private: - std::unique_ptr m_leftHand; - std::unique_ptr m_rightHand; + std::unique_ptr leftHand_; + std::unique_ptr rightHand_; /** * returns the configuration set in VRSettings for the device role given **/ - VRDeviceConfiguration_t GetDeviceConfiguration(vr::ETrackedControllerRole role); + static VRDeviceConfiguration GetDeviceConfiguration(vr::ETrackedControllerRole role); - std::unique_ptr InstantiateDeviceDriver(VRDeviceConfiguration_t configuration, std::shared_ptr boneAnimator); + std::unique_ptr InstantiateDeviceDriver(VRDeviceConfiguration configuration, std::shared_ptr boneAnimator) const; }; \ No newline at end of file diff --git a/include/DriverLog.h b/include/DriverLog.h index 9cb20e4c..ad2221b5 100644 --- a/include/DriverLog.h +++ b/include/DriverLog.h @@ -1,8 +1,3 @@ -//========= Copyright Valve Corporation ============// - -#ifndef DRIVERLOG_H -#define DRIVERLOG_H - #pragma once #include @@ -11,16 +6,7 @@ extern void DriverLog(const char* pchFormat, ...); - -// -------------------------------------------------------------------------- -// Purpose: Write to the log file only in debug builds -// -------------------------------------------------------------------------- extern void DebugDriverLog(const char* pchFormat, ...); - extern bool InitDriverLog(vr::IVRDriverLog* pDriverLog); extern void CleanupDriverLog(); - - - -#endif // DRIVERLOG_H \ No newline at end of file diff --git a/include/Encode/AlphaEncodingManager.h b/include/Encode/AlphaEncodingManager.h index ea04534a..043df5ef 100644 --- a/include/Encode/AlphaEncodingManager.h +++ b/include/Encode/AlphaEncodingManager.h @@ -2,15 +2,10 @@ #include "Encode/EncodingManager.h" -static const char* c_alphaEncodingSettingsSection = "encoding_alpha"; +class AlphaEncodingManager : public EncodingManager { + public: + explicit AlphaEncodingManager(float maxAnalogValue); -class AlphaEncodingManager : public IEncodingManager { -public: - AlphaEncodingManager(float maxAnalogValue) : m_maxAnalogValue(maxAnalogValue){}; - - //decode the given string into a VRCommData_t - VRCommData_t Decode(std::string input); - std::string Encode(const VRFFBData_t& input); - - float m_maxAnalogValue; + VRInputData Decode(std::string input) override; + std::string Encode(const VRFFBData& input) override; }; \ No newline at end of file diff --git a/include/Encode/EncodingManager.h b/include/Encode/EncodingManager.h index d555fe83..c8f19160 100644 --- a/include/Encode/EncodingManager.h +++ b/include/Encode/EncodingManager.h @@ -1,56 +1,72 @@ #pragma once + #include +#include #include -#include "ForceFeedback.h" - -struct VRCommData_t { - VRCommData_t(){}; - VRCommData_t(std::array flexion, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool menu, - bool calibrate) - : flexion(flexion), - joyX(joyX), - joyY(joyY), - joyButton(joyButton), - trgButton(trgButton), - aButton(aButton), - bButton(bButton), - grab(grab), - pinch(pinch), - menu(menu), - calibrate(calibrate){}; - const std::array flexion = {0, 0, 0, 0, 0}; - const float joyX = 500; - const float joyY = 500; - const bool joyButton = false; - const bool trgButton = false; - const bool aButton = false; - const bool bButton = false; - const bool grab = false; - const bool pinch = false; - const bool menu = false; - const bool calibrate = false; +#include "DriverLog.h" + +struct VRFFBData { + VRFFBData(); + VRFFBData(short thumbCurl, short indexCurl, short middleCurl, short ringCurl, short pinkyCurl); + + const short thumbCurl; + const short indexCurl; + const short middleCurl; + const short ringCurl; + const short pinkyCurl; }; -class IEncodingManager { +struct VRInputData { + VRInputData(); + VRInputData( + std::array flexion, + float joyX, + float joyY, + bool joyButton, + bool trgButton, + bool aButton, + bool bButton, + bool grab, + bool pinch, + bool menu, + bool calibrate); + + const std::array flexion; + const float joyX; + const float joyY; + const bool joyButton; + const bool trgButton; + const bool aButton; + const bool bButton; + const bool grab; + const bool pinch; + const bool menu; + const bool calibrate; +}; + +class EncodingManager { public: - virtual VRCommData_t Decode(std::string input) = 0; - virtual std::string Encode(const VRFFBData_t& data) = 0; - virtual ~IEncodingManager(){}; + explicit EncodingManager(float maxAnalogValue); + virtual VRInputData Decode(std::string input) = 0; + virtual std::string Encode(const VRFFBData& data) = 0; - private: - float m_maxAnalogValue = 0.0; + protected: + float maxAnalogValue_; }; template -std::string string_format(const std::string& format, Args... args) { - int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' - if (size_s <= 0) { +std::string StringFormat(const std::string& format, Args... args) { + const int sizeS = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' + + if (sizeS <= 0) { DriverLog("Error decoding string"); return ""; } - auto size = static_cast(size_s); - auto buf = std::make_unique(size); + + const auto size = static_cast(sizeS); + const auto buf = std::make_unique(size); std::snprintf(buf.get(), size, format.c_str(), args...); + return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside } diff --git a/include/Encode/LegacyEncodingManager.h b/include/Encode/LegacyEncodingManager.h index 46df6ac9..672d806b 100644 --- a/include/Encode/LegacyEncodingManager.h +++ b/include/Encode/LegacyEncodingManager.h @@ -1,18 +1,11 @@ #pragma once -#include -#include "ForceFeedback.h" +#include "Encode/EncodingManager.h" -static const char* c_legacyEncodingSettingsSection = "encoding_legacy"; - -class LegacyEncodingManager : public IEncodingManager { +class LegacyEncodingManager : public EncodingManager { public: - LegacyEncodingManager(float maxAnalogValue) : m_maxAnalogValue(maxAnalogValue){}; - - VRCommData_t Decode(std::string input); - - std::string Encode(const VRFFBData_t& input); + explicit LegacyEncodingManager(float maxAnalogValue); - private: - float m_maxAnalogValue; + VRInputData Decode(std::string input) override; + std::string Encode(const VRFFBData& input) override; }; \ No newline at end of file diff --git a/include/ForceFeedback.h b/include/ForceFeedback.h index 5d49180c..c1b2182a 100644 --- a/include/ForceFeedback.h +++ b/include/ForceFeedback.h @@ -1,31 +1,21 @@ #pragma once -#include #include +#include +#include "Encode/EncodingManager.h" +#include "Util/NamedPipeListener.h" #include "openvr_driver.h" -#include "Util/NamedPipe.h" - -struct VRFFBData_t { - VRFFBData_t(short thumbCurl, short indexCurl, short middleCurl, short ringCurl, short pinkyCurl) - : thumbCurl(thumbCurl), indexCurl(indexCurl), middleCurl(middleCurl), ringCurl(ringCurl), pinkyCurl(pinkyCurl){}; - - short thumbCurl; - short indexCurl; - short middleCurl; - short ringCurl; - short pinkyCurl; -}; class FFBListener { public: - FFBListener(std::function callback, vr::ETrackedControllerRole role); + FFBListener(std::function callback, vr::ETrackedControllerRole role); void Start(); - void Stop(); + void Stop() const; private: - std::function m_callback; - vr::ETrackedControllerRole m_role; + std::function callback_; + vr::ETrackedControllerRole role_; - std::unique_ptr m_pipe; + std::unique_ptr> pipe_; }; \ No newline at end of file diff --git a/include/Util/Logic.h b/include/Util/Logic.h new file mode 100644 index 00000000..98e47e50 --- /dev/null +++ b/include/Util/Logic.h @@ -0,0 +1,5 @@ +#pragma once +#include +#include + +bool Retry(const std::function& func, short attempts, short timeout); \ No newline at end of file diff --git a/include/Util/NamedPipe.h b/include/Util/NamedPipe.h deleted file mode 100644 index 672ee8aa..00000000 --- a/include/Util/NamedPipe.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include -#include -#include - -typedef struct { - OVERLAPPED oOverlap; - HANDLE hPipeInst; - LPVOID chRequest; - DWORD cbRead; - DWORD cbToWrite; - std::function callback; -} PIPEINST, *LPPIPEINST; - -class NamedPipeUtil { - public: - NamedPipeUtil(std::string pipeName, size_t pipeSize); - ~NamedPipeUtil(); - - bool Start(const std::function& callback); - void Stop(); - - private: - void PipeListenerThread(const std::function& callback); - void ClosePipe(); - bool CreateAndConnectInstance(LPOVERLAPPED lpo, std::string& pipeName); - bool ConnectToNewClient(LPOVERLAPPED lpo); - - std::string m_pipeName; - size_t m_pipeSize; - - HANDLE m_hPipe; - - std::thread m_pipeThread; - - std::atomic m_listenerActive; - std::atomic m_clientConnected; - LPPIPEINST m_lpPipeInst; -}; \ No newline at end of file diff --git a/include/Util/NamedPipeListener.h b/include/Util/NamedPipeListener.h new file mode 100644 index 00000000..84e9f616 --- /dev/null +++ b/include/Util/NamedPipeListener.h @@ -0,0 +1,218 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include "DriverLog.h" +#include "Util/Windows.h" + +static const int c_namedPipeDelay = 5; + +enum class NamedPipeListenerState { Connecting, Reading, Callback }; + +template +struct NamedPipeListenerData { + OVERLAPPED oOverlap; + HANDLE hPipeInst; + bool fPendingIO; + NamedPipeListenerState state; + DWORD dwBytesRead; + std::function callback; + char chRequest[sizeof(T)]; +}; + +template +class NamedPipeListener { + public: + explicit NamedPipeListener(std::string pipeName); + ~NamedPipeListener(); + + bool StartListening(const std::function& callback); + void StopListening(); + bool IsConnected() const; + void LogError(const char* error) const; + void LogMessage(const char* message) const; + + private: + bool Connect(NamedPipeListenerData* data); + void DisconnectAndReconnect(NamedPipeListenerData* data); + void ListenerThread(const std::function& callback); + + const std::string pipeName_; + + std::atomic threadActive_; + std::thread thread_; +}; + +template +NamedPipeListener::NamedPipeListener(std::string pipeName) : pipeName_(std::move(pipeName)), threadActive_(false) {} + +template +NamedPipeListener::~NamedPipeListener() { + StopListening(); +} + +template +bool NamedPipeListener::StartListening(const std::function& callback) { + if (threadActive_.exchange(true)) + // Thread already running + return false; + + thread_ = std::thread(&NamedPipeListener::ListenerThread, this, callback); + + return true; +} + +template +void NamedPipeListener::StopListening() { + if (threadActive_.exchange(false)) + // Thread running + thread_.join(); +} + +template +bool NamedPipeListener::Connect(NamedPipeListenerData* data) { + if (!ConnectNamedPipe(data->hPipeInst, &data->oOverlap)) { + switch (GetLastError()) { + case ERROR_IO_PENDING: + data->fPendingIO = true; + data->state = NamedPipeListenerState::Connecting; + return true; + + case ERROR_PIPE_CONNECTED: + if (SetEvent(data->oOverlap.hEvent)) { + data->fPendingIO = false; + data->state = NamedPipeListenerState::Reading; + return true; + } + break; + } + } + + LogError("Failed to connect"); + data->fPendingIO = false; + data->state = NamedPipeListenerState::Reading; + + return false; +} + +template +void NamedPipeListener::DisconnectAndReconnect(NamedPipeListenerData* data) { + LogMessage("Disconnecting and reconnecting named pipe"); + if (!DisconnectNamedPipe(data->hPipeInst)) LogError("Failed to disconnect"); + + if (!Connect(data)) LogError("Error reconnecting to pipe from disconnect"); +} + +template +void NamedPipeListener::ListenerThread(const std::function& callback) { + HANDLE hEvent = CreateEventA(nullptr, TRUE, TRUE, nullptr); + if (hEvent == nullptr) { + LogError("CreateEvent failed"); + return; + } + + HANDLE hPipeInst = CreateNamedPipeA( + pipeName_.c_str(), // pipe name + PIPE_ACCESS_DUPLEX | // read/write access + FILE_FLAG_OVERLAPPED, // overlapped mode + PIPE_TYPE_MESSAGE | // message-type pipe + PIPE_READMODE_MESSAGE | // message read mode + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // unlimited instances + static_cast(sizeof(T)), // output buffer size + static_cast(sizeof(T)), // input buffer size + c_namedPipeDelay, // client time-out + nullptr); // default security attributes + if (hPipeInst == INVALID_HANDLE_VALUE) { + LogError("CreateNamedPipe failed"); + CloseHandle(hEvent); + return; + } + + NamedPipeListenerData listenerData{}; + listenerData.oOverlap.hEvent = hEvent; + listenerData.hPipeInst = hPipeInst; + + if (!Connect(&listenerData)) return; + + LogMessage("Successfully connected to pipe"); + while (threadActive_) { + switch (const DWORD dwWaitResult = WaitForSingleObject(listenerData.oOverlap.hEvent, c_namedPipeDelay)) { + case WAIT_OBJECT_0: + break; + case WAIT_TIMEOUT: + continue; + default: + LogError("WaitForSingleObject failed"); + DisconnectAndReconnect(&listenerData); + continue; + } + + if (listenerData.fPendingIO) { + DWORD dwBytesTransferred = 0; + const BOOL fSuccess = GetOverlappedResult(listenerData.hPipeInst, &listenerData.oOverlap, &dwBytesTransferred, FALSE); + if (listenerData.state == NamedPipeListenerState::Reading) { + if (!fSuccess || dwBytesTransferred == 0) { + LogError("GetOverlappedResult failed"); + DisconnectAndReconnect(&listenerData); + continue; + } + listenerData.fPendingIO = false; + listenerData.state = NamedPipeListenerState::Callback; + listenerData.dwBytesRead = dwBytesTransferred; + } else { // Connecting/Callback/etc. + if (!fSuccess) { + LogError("GetOverlappedResult failed"); + break; + } + listenerData.state = NamedPipeListenerState::Reading; + } + } + + if (listenerData.state == NamedPipeListenerState::Reading) { + if (ReadFile(listenerData.hPipeInst, listenerData.chRequest, sizeof(T), &listenerData.dwBytesRead, &listenerData.oOverlap)) { + if (listenerData.dwBytesRead > 0) { + listenerData.fPendingIO = false; + listenerData.state = NamedPipeListenerState::Callback; + } else + DisconnectAndReconnect(&listenerData); + } else { + if (GetLastError() == ERROR_IO_PENDING) + listenerData.fPendingIO = true; + else { + LogError("Pipe received data but failed to read"); + DisconnectAndReconnect(&listenerData); + } + } + } else { // Callback (see above) + if (listenerData.dwBytesRead == sizeof(T)) { + callback((T*)listenerData.chRequest); + listenerData.state = NamedPipeListenerState::Reading; + } else + DisconnectAndReconnect(&listenerData); + } + } + + CloseHandle(hPipeInst); + CloseHandle(hEvent); +} + +template +bool NamedPipeListener::IsConnected() const { + return threadActive_; +} + +template +void NamedPipeListener::LogError(const char* error) const { + DriverLog("%s (%s) - Error: %s", error, pipeName_.c_str(), GetLastErrorAsString().c_str()); +} + +template +void NamedPipeListener::LogMessage(const char* message) const { + DriverLog("%s (%s)", message, pipeName_.c_str()); +} diff --git a/include/Quaternion.h b/include/Util/Quaternion.h similarity index 50% rename from include/Quaternion.h rename to include/Util/Quaternion.h index 16d5d61e..237d9f31 100644 --- a/include/Quaternion.h +++ b/include/Util/Quaternion.h @@ -5,23 +5,19 @@ double DegToRad(double degrees); double RadToDeg(double rad); - - -//get the quaternion for roation from a matrix +// get the quaternion for rotation from a matrix vr::HmdQuaternion_t GetRotation(const vr::HmdMatrix34_t& matrix); vr::HmdVector3_t GetPosition(const vr::HmdMatrix34_t& matrix); vr::HmdVector3_t CombinePosition(const vr::HmdMatrix34_t& matrix, const vr::HmdVector3_t& vec); -//returns the result of multiplying two quaternions, effectively applying a roatation on a quaternion +// returns the result of multiplying two quaternions, effectively applying a rotation on a quaternion vr::HmdQuaternion_t MultiplyQuaternion(const vr::HmdQuaternion_t& q, const vr::HmdQuaternion_t& r); -vr::HmdQuaternion_t QuaternionFromAngle(const double& xx, const double& yy, const double& zz, const double& a); -vr::HmdQuaternion_t EulerToQuaternion(const double& x, const double& y, const double& z); +vr::HmdQuaternion_t EulerToQuaternion(const double& yaw, const double& pitch, const double& roll); vr::HmdMatrix33_t GetRotationMatrix(const vr::HmdMatrix34_t& matrix); vr::HmdVector3_t MultiplyMatrix(const vr::HmdMatrix33_t& matrix, const vr::HmdVector3_t& vector); -vr::HmdMatrix33_t QuaternionToMatrix(const vr::HmdQuaternion_t q); +vr::HmdMatrix33_t QuaternionToMatrix(const vr::HmdQuaternion_t& q); -double QuatNorm(const vr::HmdQuaternion_t q); -vr::HmdQuaternion_t QuatConjugate(const vr::HmdQuaternion_t q); +vr::HmdQuaternion_t QuatConjugate(const vr::HmdQuaternion_t& q); -vr::HmdVector3_t QuaternionToEuler(const vr::HmdQuaternion_t q); \ No newline at end of file +vr::HmdVector3_t QuaternionToEuler(const vr::HmdQuaternion_t& q); \ No newline at end of file diff --git a/include/Util/Windows.h b/include/Util/Windows.h index 5881399e..fa5514f2 100644 --- a/include/Util/Windows.h +++ b/include/Util/Windows.h @@ -3,4 +3,5 @@ #include extern std::string GetDriverPath(); -extern std::string GetLastErrorAsString(); \ No newline at end of file +extern std::string GetLastErrorAsString(); +extern bool CreateBackgroundProcess(const std::string& path); \ No newline at end of file diff --git a/openglove/resources/settings/default.vrsettings b/openglove/resources/settings/default.vrsettings index 05c7ea7f..d0cc7325 100644 --- a/openglove/resources/settings/default.vrsettings +++ b/openglove/resources/settings/default.vrsettings @@ -1,9 +1,9 @@ { - "driver_openglove": - { + "driver_openglove": { "__title": "OpenGlove Configuration", "left_enabled": true, "right_enabled": true, + "feedback_enabled": true, "communication_protocol": 0, //title:Communication Method "device_driver": 1, //title:Device Driver Emulation "encoding_protocol": 1 //title:Encoding Protocol @@ -20,11 +20,13 @@ "__title": "Knuckles Emulation", "__type": "device_driver:1", "left_serial_number": "LHR-E217CD00", - "right_serial_number": "LHR-E217CD01" + "right_serial_number": "LHR-E217CD01", + "approximate_thumb": true }, "pose_settings": { "__title": "Pose settings", + "hardware_calibration_button_enabled": false, "right_x_offset_position": -0.1, "right_y_offset_position": -0.08, "right_z_offset_position": -0.03, @@ -54,8 +56,13 @@ { "__type": "communication_protocol:1", "__title": "Bluetooth Serial", - "left_name": "lucidgloves-left", - "right_name": "lucidgloves-right" + "left_name": "lucidgloves-left", + "right_name": "lucidgloves-right" + }, + "communication_namedpipe": + { + "__type": "communication_protocol:2", + "__title": "Named Pipe" }, "encoding_legacy": { @@ -69,4 +76,4 @@ "__title": "Alpha Protocol", "max_analog_value": 4095 } -} +} \ No newline at end of file diff --git a/overlay/main.cpp b/overlay/main.cpp index 936a2f12..08726244 100644 --- a/overlay/main.cpp +++ b/overlay/main.cpp @@ -9,17 +9,21 @@ std::atomic appActive = true; const std::string ourManufacturer = "LucidVR"; std::string GetLastErrorAsString() { - DWORD errorMessageID = ::GetLastError(); - if (errorMessageID == 0) { + const DWORD errorMessageId = ::GetLastError(); + if (errorMessageId == 0) { return std::string(); } LPSTR messageBuffer = nullptr; - size_t size = FormatMessageA( + const size_t size = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, - NULL); + nullptr, + errorMessageId, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&messageBuffer), + 0, + nullptr); std::string message(messageBuffer, size); @@ -28,14 +32,14 @@ std::string GetLastErrorAsString() { return message; } -void GetAndSendControllerId(int id, vr::ETrackedControllerRole role) { - std::unique_ptr pipeHelper = std::make_unique(); +void GetAndSendControllerId(const vr::TrackedDeviceIndex_t id, const vr::ETrackedControllerRole role) { + const auto pipeHelper = std::make_unique(); std::string pipeName; if (role == vr::ETrackedControllerRole::TrackedControllerRole_LeftHand) { - pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\left"; + pipeName = R"(\\.\pipe\vrapplication\discovery\left)"; } else { - pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\right"; + pipeName = R"(\\.\pipe\vrapplication\discovery\right)"; } ControllerPipeData data{}; @@ -44,41 +48,37 @@ void GetAndSendControllerId(int id, vr::ETrackedControllerRole role) { pipeHelper->ConnectAndSendPipe(pipeName, data); } -void DiscoverController(vr::ETrackedControllerRole role) { - int lastFound = -1; - int curFound = -1; +void DiscoverController(const vr::ETrackedControllerRole role) { + vr::TrackedDeviceIndex_t lastFound = -1; + vr::TrackedDeviceIndex_t curFound = -1; while (appActive) { - for (int32_t i = 1; i < vr::k_unMaxTrackedDeviceCount; i++) { + for (vr::TrackedDeviceIndex_t i = 1; i < vr::k_unMaxTrackedDeviceCount; i++) { char thisManufacturer[1024]; uint32_t err = vr::VRSystem()->GetStringTrackedDeviceProperty( - i, vr::ETrackedDeviceProperty::Prop_ManufacturerName_String, thisManufacturer, - sizeof(thisManufacturer)); + i, vr::ETrackedDeviceProperty::Prop_ManufacturerName_String, thisManufacturer, sizeof thisManufacturer); std::string sThisManufacturer(thisManufacturer); if (ourManufacturer == sThisManufacturer) continue; - short deviceRole = vr::VRSystem()->GetControllerRoleForTrackedDeviceIndex(i); + const short deviceRole = vr::VRSystem()->GetControllerRoleForTrackedDeviceIndex(i); - int32_t controllerHint = vr::VRSystem()->GetInt32TrackedDeviceProperty( - i, vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32); + const int32_t controllerHint = vr::VRSystem()->GetInt32TrackedDeviceProperty(i, vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32); if (controllerHint == role) { curFound = i; break; } - - int controllerType = vr::VRSystem()->GetInt32TrackedDeviceProperty( - i, vr::ETrackedDeviceProperty::Prop_DeviceClass_Int32); + + const int controllerType = vr::VRSystem()->GetInt32TrackedDeviceProperty(i, vr::ETrackedDeviceProperty::Prop_DeviceClass_Int32); if (controllerType == vr::ETrackedDeviceClass::TrackedDeviceClass_GenericTracker || controllerType == vr::ETrackedDeviceClass::TrackedDeviceClass_Controller) { if (role == deviceRole) { - curFound = i; + curFound = i; } } - } if (curFound != lastFound) { @@ -94,14 +94,12 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL VR_Init(&error, vr::VRApplication_Background); if (error == vr::EVRInitError::VRInitError_None) { - std::thread leftControllerThread = std::thread( - &DiscoverController, vr::ETrackedControllerRole::TrackedControllerRole_LeftHand); + auto leftControllerThread = std::thread(&DiscoverController, vr::ETrackedControllerRole::TrackedControllerRole_LeftHand); - std::thread rightControllerThread = std::thread( - &DiscoverController, vr::ETrackedControllerRole::TrackedControllerRole_RightHand); + auto rightControllerThread = std::thread(&DiscoverController, vr::ETrackedControllerRole::TrackedControllerRole_RightHand); while (appActive) { - vr::VREvent_t event; + vr::VREvent_t event{}; while (vr::VRSystem() && vr::VRSystem()->PollNextEvent(&event, sizeof event)) { switch (event.eventType) { case vr::VREvent_Quit: @@ -123,20 +121,20 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL return 0; } -PipeHelper::PipeHelper() : m_pipeHandle(NULL) {} +PipeHelper::PipeHelper() : pipeHandle_(nullptr) {} bool PipeHelper::ConnectAndSendPipe(const std::string& pipeName, ControllerPipeData data) { - while (1) { - m_pipeHandle = CreateFile(pipeName.c_str(), // pipe name - GENERIC_READ | // read and write access - GENERIC_WRITE, - 0, // no sharing - NULL, // default security attributes - OPEN_EXISTING, // opens existing pipe - 0, // default attributes - NULL); // no template file - - if (m_pipeHandle != INVALID_HANDLE_VALUE) break; + while (true) { + pipeHandle_ = CreateFile( + pipeName.c_str(), // pipe name + GENERIC_READ | GENERIC_WRITE, // read and write access + 0, // no sharing + nullptr, // default security attributes + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + nullptr); // no template file + + if (pipeHandle_ != INVALID_HANDLE_VALUE) break; if (GetLastError() != ERROR_PIPE_BUSY) { return false; @@ -149,9 +147,9 @@ bool PipeHelper::ConnectAndSendPipe(const std::string& pipeName, ControllerPipeD DWORD dwWritten; - WriteFile(m_pipeHandle, (LPCVOID)&data, sizeof(ControllerPipeData), &dwWritten, NULL); + WriteFile(pipeHandle_, &data, sizeof(ControllerPipeData), &dwWritten, nullptr); - CloseHandle(m_pipeHandle); + CloseHandle(pipeHandle_); return true; } \ No newline at end of file diff --git a/overlay/main.h b/overlay/main.h index bc6b0e51..3883136d 100644 --- a/overlay/main.h +++ b/overlay/main.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include struct ControllerPipeData { short controllerId; @@ -13,5 +13,5 @@ class PipeHelper { bool ConnectAndSendPipe(const std::string& pipeName, ControllerPipeData data); private: - HANDLE m_pipeHandle; + HANDLE pipeHandle_; }; \ No newline at end of file diff --git a/src/Bones.cpp b/src/Bones.cpp index 84850f3b..8355e95a 100644 --- a/src/Bones.cpp +++ b/src/Bones.cpp @@ -1,5 +1,7 @@ #include "Bones.h" +#include + #include "DriverLog.h" #define TINYGLTF_IMPLEMENTATION @@ -10,48 +12,87 @@ static const std::array emptyRotation = {0.0f, 0.0f, 0.0f, 0.0f}; static const std::array emptyTranslation = {0.0f, 0.0f, 0.0f}; -Transform_t::Transform_t() : rotation(emptyRotation), translation(emptyTranslation) {} -AnimationData_t::AnimationData_t() : startTime(0.0f), endTime(0.0f) {} +Transform::Transform() : rotation(emptyRotation), translation(emptyTranslation) {} +AnimationData::AnimationData() : startTime(0.0f), endTime(0.0f) {} -static float Lerp(const float& a, const float& b, const float& f) { return a + f * (b - a); } +static float Lerp(const float& a, const float& b, const float& f) { + return a + f * (b - a); +} enum class FingerIndex : int { Thumb = 0, IndexFinger, MiddleFinger, RingFinger, PinkyFinger, Unknown = -1 }; -static FingerIndex GetFingerFromBoneIndex(HandSkeletonBone bone) { +static std::map GLTFNodeBoneMap{ + {"REF:Root", HandSkeletonBone::Root}, + {"REF:wrist_r", HandSkeletonBone::Wrist}, + {"REF:finger_thumb_0_r", HandSkeletonBone::Thumb0}, + {"REF:finger_thumb_1_r", HandSkeletonBone::Thumb1}, + {"REF:finger_thumb_2_r", HandSkeletonBone::Thumb2}, + {"REF:finger_thumb_r_end", HandSkeletonBone::Thumb3}, + {"REF:finger_index_meta_r", HandSkeletonBone::IndexFinger0}, + {"REF:finger_index_0_r", HandSkeletonBone::IndexFinger1}, + {"REF:finger_index_1_r", HandSkeletonBone::IndexFinger2}, + {"REF:finger_index_2_r", HandSkeletonBone::IndexFinger3}, + {"REF:finger_index_r_end", HandSkeletonBone::IndexFinger4}, + {"REF:finger_middle_meta_r", HandSkeletonBone::MiddleFinger0}, + {"REF:finger_middle_0_r", HandSkeletonBone::MiddleFinger1}, + {"REF:finger_middle_1_r", HandSkeletonBone::MiddleFinger2}, + {"REF:finger_middle_2_r", HandSkeletonBone::MiddleFinger3}, + {"REF:finger_middle_r_end", HandSkeletonBone::MiddleFinger4}, + {"REF:finger_ring_meta_r", HandSkeletonBone::RingFinger0}, + {"REF:finger_ring_0_r", HandSkeletonBone::RingFinger1}, + {"REF:finger_ring_1_r", HandSkeletonBone::RingFinger2}, + {"REF:finger_ring_2_r", HandSkeletonBone::RingFinger3}, + {"REF:finger_ring_r_end", HandSkeletonBone::RingFinger4}, + {"REF:finger_pinky_meta_r", HandSkeletonBone::PinkyFinger0}, + {"REF:finger_pinky_0_r", HandSkeletonBone::PinkyFinger1}, + {"REF:finger_pinky_1_r", HandSkeletonBone::PinkyFinger2}, + {"REF:finger_pinky_2_r", HandSkeletonBone::PinkyFinger3}, + {"REF:finger_pinky_r_end", HandSkeletonBone::PinkyFinger4}, + {"REF:finger_thumb_r_aux", HandSkeletonBone::AuxThumb}, + {"REF:finger_index_r_aux", HandSkeletonBone::AuxIndexFinger}, + {"REF:finger_middle_r_aux", HandSkeletonBone::AuxMiddleFinger}, + {"REF:finger_ring_r_aux", HandSkeletonBone::AuxRingFinger}, + {"REF:finger_pinky_r_aux", HandSkeletonBone::AuxPinkyFinger}}; + +static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone bone) { switch (bone) { - case HandSkeletonBone::eBone_Thumb0: - case HandSkeletonBone::eBone_Thumb1: - case HandSkeletonBone::eBone_Thumb2: - case HandSkeletonBone::eBone_Thumb3: - case HandSkeletonBone::eBone_Aux_Thumb: + case HandSkeletonBone::Thumb0: + case HandSkeletonBone::Thumb1: + case HandSkeletonBone::Thumb2: + case HandSkeletonBone::Thumb3: + case HandSkeletonBone::AuxThumb: return FingerIndex::Thumb; - case HandSkeletonBone::eBone_IndexFinger0: - case HandSkeletonBone::eBone_IndexFinger1: - case HandSkeletonBone::eBone_IndexFinger2: - case HandSkeletonBone::eBone_IndexFinger3: - case HandSkeletonBone::eBone_IndexFinger4: - case HandSkeletonBone::eBone_Aux_IndexFinger: + + case HandSkeletonBone::IndexFinger0: + case HandSkeletonBone::IndexFinger1: + case HandSkeletonBone::IndexFinger2: + case HandSkeletonBone::IndexFinger3: + case HandSkeletonBone::IndexFinger4: + case HandSkeletonBone::AuxIndexFinger: return FingerIndex::IndexFinger; - case HandSkeletonBone::eBone_MiddleFinger0: - case HandSkeletonBone::eBone_MiddleFinger1: - case HandSkeletonBone::eBone_MiddleFinger2: - case HandSkeletonBone::eBone_MiddleFinger3: - case HandSkeletonBone::eBone_MiddleFinger4: - case HandSkeletonBone::eBone_Aux_MiddleFinger: + + case HandSkeletonBone::MiddleFinger0: + case HandSkeletonBone::MiddleFinger1: + case HandSkeletonBone::MiddleFinger2: + case HandSkeletonBone::MiddleFinger3: + case HandSkeletonBone::MiddleFinger4: + case HandSkeletonBone::AuxMiddleFinger: return FingerIndex::MiddleFinger; - case HandSkeletonBone::eBone_RingFinger0: - case HandSkeletonBone::eBone_RingFinger1: - case HandSkeletonBone::eBone_RingFinger2: - case HandSkeletonBone::eBone_RingFinger3: - case HandSkeletonBone::eBone_RingFinger4: - case HandSkeletonBone::eBone_Aux_RingFinger: + + case HandSkeletonBone::RingFinger0: + case HandSkeletonBone::RingFinger1: + case HandSkeletonBone::RingFinger2: + case HandSkeletonBone::RingFinger3: + case HandSkeletonBone::RingFinger4: + case HandSkeletonBone::AuxRingFinger: return FingerIndex::RingFinger; - case HandSkeletonBone::eBone_PinkyFinger0: - case HandSkeletonBone::eBone_PinkyFinger1: - case HandSkeletonBone::eBone_PinkyFinger2: - case HandSkeletonBone::eBone_PinkyFinger3: - case HandSkeletonBone::eBone_PinkyFinger4: - case HandSkeletonBone::eBone_Aux_PinkyFinger: + + case HandSkeletonBone::PinkyFinger0: + case HandSkeletonBone::PinkyFinger1: + case HandSkeletonBone::PinkyFinger2: + case HandSkeletonBone::PinkyFinger3: + case HandSkeletonBone::PinkyFinger4: + case HandSkeletonBone::AuxPinkyFinger: return FingerIndex::PinkyFinger; default: @@ -60,22 +101,21 @@ static FingerIndex GetFingerFromBoneIndex(HandSkeletonBone bone) { } class GLTFModelManager : public IModelManager { - private: - tinygltf::Model m_model; - std::string m_fileName; - std::vector m_initialTransforms; - std::vector m_keyframeTimes; - std::vector> m_keyframeTransforms; + tinygltf::Model model_; + std::string fileName_; + std::vector initialTransforms_; + std::vector keyframeTimes_; + std::vector> keyframeTransforms_; public: - GLTFModelManager(const std::string& fileName) : m_fileName(fileName) {} + GLTFModelManager(std::string fileName) : fileName_(std::move(fileName)) {} - bool Load() { + bool Load() override { tinygltf::TinyGLTF loader; std::string err; std::string warn; - bool ret = loader.LoadBinaryFromFile(&m_model, &err, &warn, m_fileName); + const bool ret = loader.LoadBinaryFromFile(&model_, &err, &warn, fileName_); if (!warn.empty()) { DriverLog("Warning parsing gltf file: %s", warn.c_str()); @@ -92,176 +132,188 @@ class GLTFModelManager : public IModelManager { return false; } - m_initialTransforms = std::vector(m_model.nodes.size()-1); - m_keyframeTransforms = std::vector>(m_model.nodes.size()-1); + initialTransforms_ = std::vector(GLTFNodeBoneMap.size()); + keyframeTransforms_ = std::vector>(GLTFNodeBoneMap.size()); - LoadInitialTransforms(); LoadKeyframeTimes(); - LoadKeyframeTransforms(); + LoadInitialTransforms(); return true; } - AnimationData_t GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, float f) const { - const size_t lowerKeyframeIndex = std::lower_bound(m_keyframeTimes.begin(), m_keyframeTimes.end(), std::clamp(f, 0.0001f, 1.0f)) - m_keyframeTimes.begin() - 1; - const size_t upperKeyframeIndex = (lowerKeyframeIndex < m_keyframeTimes.size() - 1) ? (lowerKeyframeIndex + 1) : lowerKeyframeIndex; + AnimationData GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, const float f) const override { + const float smallest = keyframeTimes_.at(0); + const float largest = keyframeTimes_.at(keyframeTimes_.size() - 1); + const float fScaled = Lerp(smallest, largest, f); + + const size_t lowerKeyframeIndex = std::upper_bound(keyframeTimes_.begin(), keyframeTimes_.end(), fScaled) - keyframeTimes_.begin() - 1; + const size_t upperKeyframeIndex = lowerKeyframeIndex < keyframeTimes_.size() - 1 ? lowerKeyframeIndex + 1 : lowerKeyframeIndex; + + AnimationData result; + result.startTransform = keyframeTransforms_[static_cast(boneIndex)][lowerKeyframeIndex]; + result.startTime = keyframeTimes_[lowerKeyframeIndex]; + result.endTransform = keyframeTransforms_[static_cast(boneIndex)][upperKeyframeIndex]; + result.endTime = keyframeTimes_[upperKeyframeIndex]; + result.fScaled = fScaled; - AnimationData_t result; - result.startTransform = m_keyframeTransforms[(size_t)boneIndex][lowerKeyframeIndex]; - result.startTime = m_keyframeTimes[lowerKeyframeIndex]; - result.endTransform = m_keyframeTransforms[(size_t)boneIndex][upperKeyframeIndex]; - result.endTime = m_keyframeTimes[upperKeyframeIndex]; return result; } - Transform_t GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const { return m_initialTransforms[(size_t)boneIndex]; } + Transform GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const override { + return initialTransforms_[static_cast(boneIndex)]; + } private: void LoadInitialTransforms() { - for (size_t nodeIndex = 1; nodeIndex < m_model.nodes.size(); nodeIndex++) { - tinygltf::Node node = m_model.nodes[nodeIndex]; - - Transform_t transform; - if (node.rotation.size() >= 4) { - transform.rotation[0] = (float)node.rotation[0]; - transform.rotation[1] = (float)node.rotation[1]; - transform.rotation[2] = (float)node.rotation[2]; - transform.rotation[3] = (float)node.rotation[3]; - } - if (node.translation.size() >= 3) { - transform.translation[0] = (float)node.translation[0]; - transform.translation[1] = (float)node.translation[1]; - transform.translation[2] = (float)node.translation[2]; - } + for (size_t nodeIndex = 0; nodeIndex < model_.nodes.size(); nodeIndex++) { + const tinygltf::Node& node = model_.nodes[nodeIndex]; + + try { + const int boneIndex = static_cast(GLTFNodeBoneMap.at(node.name)); + + Transform transform; + if (node.rotation.size() >= 4) { + transform.rotation[0] = static_cast(node.rotation[0]); + transform.rotation[1] = static_cast(node.rotation[1]); + transform.rotation[2] = static_cast(node.rotation[2]); + transform.rotation[3] = static_cast(node.rotation[3]); + } + if (node.translation.size() >= 3) { + transform.translation[0] = static_cast(node.translation[0]); + transform.translation[1] = static_cast(node.translation[1]); + transform.translation[2] = static_cast(node.translation[2]); + } - //first node is never needed - m_initialTransforms[nodeIndex - 1] = transform; + initialTransforms_[boneIndex] = transform; + + const tinygltf::Animation& animation = model_.animations[0]; + std::vector& transforms = keyframeTransforms_[boneIndex]; + + transforms.resize(keyframeTimes_.size()); + + for (auto& channel : animation.channels) { + if (channel.target_node != nodeIndex) continue; + + const tinygltf::Accessor& accessor = model_.accessors[animation.samplers[channel.sampler].output]; + switch (accessor.type) { + // rotation via quaternion + case TINYGLTF_TYPE_VEC4: { + std::vector> keyframes = GetVecN<4>(accessor); + for (size_t i = 0; i < keyframes.size(); i++) transforms[i].rotation = keyframes[i]; + break; + } + // translation + case TINYGLTF_TYPE_VEC3: { + std::vector> keyframes = GetVecN<3>(accessor); + for (size_t i = 0; i < keyframes.size(); i++) transforms[i].translation = keyframes[i]; + break; + } + } + } + + } catch (const std::out_of_range&) { + DriverLog("Not parsing node as it was not defined as a bone: %i", nodeIndex); + continue; + } } } void LoadKeyframeTimes() { - tinygltf::Accessor accessor = m_model.accessors[0]; - m_keyframeTimes.resize(accessor.count); + const tinygltf::Accessor accessor = model_.accessors[0]; + keyframeTimes_.resize(accessor.count); - tinygltf::BufferView bufferView = m_model.bufferViews[accessor.bufferView]; - const std::vector& bufData = m_model.buffers[0].data; - memcpy(&m_keyframeTimes[0], bufData.data() + bufferView.byteOffset + accessor.byteOffset, accessor.count * sizeof(float)); + const tinygltf::BufferView bufferView = model_.bufferViews[accessor.bufferView]; + const std::vector& bufData = model_.buffers[0].data; + memcpy(&keyframeTimes_[0], bufData.data() + bufferView.byteOffset + accessor.byteOffset, accessor.count * sizeof(float)); } template std::vector> GetVecN(const tinygltf::Accessor& accessor) const { - tinygltf::BufferView bufferView = m_model.bufferViews[accessor.bufferView]; - const std::vector& bufData = m_model.buffers[0].data; + const tinygltf::BufferView bufferView = model_.bufferViews[accessor.bufferView]; + const std::vector& bufData = model_.buffers[0].data; std::vector> res(accessor.count); memcpy(&res[0], bufData.data() + bufferView.byteOffset + accessor.byteOffset, accessor.count * sizeof(float) * N); return res; } - - void LoadKeyframeTransforms() { - for (size_t nodeIndex = 1; nodeIndex < m_model.nodes.size(); nodeIndex++) { - const tinygltf::Animation& animation = m_model.animations[0]; - - // first node is never needed - std::vector& transforms = m_keyframeTransforms[nodeIndex - 1]; - - transforms.resize(m_keyframeTimes.size()); - - for (auto& channel : animation.channels) { - if (channel.target_node != nodeIndex) continue; - - const tinygltf::Accessor& accessor = m_model.accessors[animation.samplers[channel.sampler].output]; - switch (accessor.type) { - // rotation via quaternion - case TINYGLTF_TYPE_VEC4: { - std::vector> keyframes = GetVecN<4>(accessor); - for (size_t i = 0; i < keyframes.size(); i++) transforms[i].rotation = keyframes[i]; - break; - } - // translation - case TINYGLTF_TYPE_VEC3: { - std::vector> keyframes = GetVecN<3>(accessor); - for (size_t i = 0; i < keyframes.size(); i++) transforms[i].translation = keyframes[i]; - break; - } - } - } - } - } }; -BoneAnimator::BoneAnimator(const std::string& fileName) : m_fileName(fileName) { - m_modelManager = std::make_unique(fileName); - m_loaded = m_modelManager->Load(); +BoneAnimator::BoneAnimator(const std::string& fileName) : fileName_(fileName) { + modelManager_ = std::make_unique(fileName); + loaded_ = modelManager_->Load(); } void BoneAnimator::ComputeSkeletonTransforms(vr::VRBoneTransform_t* skeleton, const std::array& flexion, const bool rightHand) { - if (!m_loaded) return; + if (!loaded_) return; for (size_t i = 0; i < NUM_BONES; i++) { - FingerIndex finger = GetFingerFromBoneIndex((HandSkeletonBone)i); - if (finger != FingerIndex::Unknown) skeleton[i] = GetTransformForBone((HandSkeletonBone)i, flexion[static_cast(finger)], rightHand); + const FingerIndex finger = GetFingerFromBoneIndex(static_cast(i)); + if (finger != FingerIndex::Unknown) { + const float f = flexion[static_cast(finger)]; + SetTransformForBone(skeleton[i], static_cast(i), f, rightHand); + } } } -vr::VRBoneTransform_t BoneAnimator::GetTransformForBone(const HandSkeletonBone& boneIndex, const float f, const bool rightHand) { - vr::VRBoneTransform_t result{}; +void BoneAnimator::SetTransformForBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex, const float f, const bool rightHand) const { + if (f < 0.0f || f > 1.0f) return; // skip if the value is invalid - Transform_t nodeTransform = m_modelManager->GetTransformByBoneIndex(boneIndex); - result.orientation.x = nodeTransform.rotation[0]; - result.orientation.y = nodeTransform.rotation[1]; - result.orientation.z = nodeTransform.rotation[2]; - result.orientation.w = nodeTransform.rotation[3]; - result.position.v[0] = nodeTransform.translation[0]; - result.position.v[1] = nodeTransform.translation[1]; - result.position.v[2] = nodeTransform.translation[2]; + const Transform nodeTransform = modelManager_->GetTransformByBoneIndex(boneIndex); + bone.orientation.x = nodeTransform.rotation[0]; + bone.orientation.y = nodeTransform.rotation[1]; + bone.orientation.z = nodeTransform.rotation[2]; + bone.orientation.w = nodeTransform.rotation[3]; + bone.position.v[0] = nodeTransform.translation[0]; + bone.position.v[1] = nodeTransform.translation[1]; + bone.position.v[2] = nodeTransform.translation[2]; - AnimationData_t animationData = m_modelManager->GetAnimationDataByBoneIndex(boneIndex, f); + const AnimationData animationData = modelManager_->GetAnimationDataByBoneIndex(boneIndex, f); - const float interp = std::clamp((f - animationData.startTime) / (animationData.endTime - animationData.startTime), 0.0f, 1.0f); + // start and end time can be the same (if we've reached the max keyframe), so make sure we only do the lerp if not + const float diff = animationData.endTime - animationData.startTime; + const float interp = diff != 0.0f ? (animationData.fScaled - animationData.startTime) / diff : 1.0f; if (animationData.startTransform.rotation != emptyRotation) { - result.orientation.x = Lerp(animationData.startTransform.rotation[0], animationData.endTransform.rotation[0], interp); - result.orientation.y = Lerp(animationData.startTransform.rotation[1], animationData.endTransform.rotation[1], interp); - result.orientation.z = Lerp(animationData.startTransform.rotation[2], animationData.endTransform.rotation[2], interp); - result.orientation.w = Lerp(animationData.startTransform.rotation[3], animationData.endTransform.rotation[3], interp); + bone.orientation.x = Lerp(animationData.startTransform.rotation[0], animationData.endTransform.rotation[0], interp); + bone.orientation.y = Lerp(animationData.startTransform.rotation[1], animationData.endTransform.rotation[1], interp); + bone.orientation.z = Lerp(animationData.startTransform.rotation[2], animationData.endTransform.rotation[2], interp); + bone.orientation.w = Lerp(animationData.startTransform.rotation[3], animationData.endTransform.rotation[3], interp); } if (animationData.startTransform.translation != emptyTranslation) { - result.position.v[0] = Lerp(animationData.startTransform.translation[0], animationData.endTransform.translation[0], interp); - result.position.v[1] = Lerp(animationData.startTransform.translation[1], animationData.endTransform.translation[1], interp); - result.position.v[2] = Lerp(animationData.startTransform.translation[2], animationData.endTransform.translation[2], interp); + bone.position.v[0] = Lerp(animationData.startTransform.translation[0], animationData.endTransform.translation[0], interp); + bone.position.v[1] = Lerp(animationData.startTransform.translation[1], animationData.endTransform.translation[1], interp); + bone.position.v[2] = Lerp(animationData.startTransform.translation[2], animationData.endTransform.translation[2], interp); } - result.position.v[3] = 1.0f; + bone.position.v[3] = 1.0f; - if (!rightHand) TransformLeftBone(result, boneIndex); - return result; + if (!rightHand) TransformLeftBone(bone, boneIndex); }; void BoneAnimator::TransformLeftBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex) { switch (boneIndex) { - case HandSkeletonBone::eBone_Root: { + case HandSkeletonBone::Root: { return; } - case HandSkeletonBone::eBone_Thumb0: - case HandSkeletonBone::eBone_IndexFinger0: - case HandSkeletonBone::eBone_MiddleFinger0: - case HandSkeletonBone::eBone_RingFinger0: - case HandSkeletonBone::eBone_PinkyFinger0: { - vr::HmdQuaternionf_t quat = bone.orientation; + case HandSkeletonBone::Thumb0: + case HandSkeletonBone::IndexFinger0: + case HandSkeletonBone::MiddleFinger0: + case HandSkeletonBone::RingFinger0: + case HandSkeletonBone::PinkyFinger0: { + const vr::HmdQuaternionf_t quat = bone.orientation; bone.orientation.w = -quat.x; bone.orientation.x = quat.w; bone.orientation.y = -quat.z; bone.orientation.z = quat.y; break; } - case HandSkeletonBone::eBone_Wrist: - case HandSkeletonBone::eBone_Aux_IndexFinger: - case HandSkeletonBone::eBone_Aux_Thumb: - case HandSkeletonBone::eBone_Aux_MiddleFinger: - case HandSkeletonBone::eBone_Aux_RingFinger: - case HandSkeletonBone::eBone_Aux_PinkyFinger: { + case HandSkeletonBone::Wrist: + case HandSkeletonBone::AuxIndexFinger: + case HandSkeletonBone::AuxThumb: + case HandSkeletonBone::AuxMiddleFinger: + case HandSkeletonBone::AuxRingFinger: + case HandSkeletonBone::AuxPinkyFinger: { bone.orientation.y *= -1; bone.orientation.z *= -1; break; diff --git a/src/Calibration.cpp b/src/Calibration.cpp index 13c4fed3..766e00dc 100644 --- a/src/Calibration.cpp +++ b/src/Calibration.cpp @@ -1,69 +1,73 @@ #include "Calibration.h" -#include "DriverLog.h" -#include "Quaternion.h" - -Calibration::Calibration() : m_maintainPose(), m_isCalibrating(false) {} - -void Calibration::StartCalibration(vr::DriverPose_t maintainPose) { - maintainPose.vecVelocity[0] = 0; - maintainPose.vecVelocity[1] = 0; - maintainPose.vecVelocity[2] = 0; - maintainPose.vecAngularVelocity[0] = 0; - maintainPose.vecAngularVelocity[1] = 0; - maintainPose.vecAngularVelocity[2] = 0; - m_maintainPose = maintainPose; - m_isCalibrating = true; +#include "Util/Quaternion.h" + +Calibration::Calibration() : maintainPose_(), isCalibrating_(false), calibratingMethod_(CalibrationMethod::None) {} + +void Calibration::StartCalibration(vr::DriverPose_t maintainPose, const CalibrationMethod method) { + calibratingMethod_ = method; + + maintainPose.vecVelocity[0] = 0; + maintainPose.vecVelocity[1] = 0; + maintainPose.vecVelocity[2] = 0; + maintainPose.vecAngularVelocity[0] = 0; + maintainPose.vecAngularVelocity[1] = 0; + maintainPose.vecAngularVelocity[2] = 0; + maintainPose_ = maintainPose; + isCalibrating_ = true; } -VRPoseConfiguration_t Calibration::CompleteCalibration(vr::TrackedDevicePose_t controllerPose, VRPoseConfiguration_t poseConfiguration, bool isRightHand) { - - m_isCalibrating = false; - // get the matrix that represents the position of the controller that we are shadowing - vr::HmdMatrix34_t controllerMatrix = controllerPose.mDeviceToAbsoluteTracking; +VRPoseConfiguration Calibration::CompleteCalibration( + const vr::TrackedDevicePose_t controllerPose, VRPoseConfiguration poseConfiguration, const bool isRightHand, const CalibrationMethod method) { + if (calibratingMethod_ != method) return poseConfiguration; - vr::HmdQuaternion_t controllerQuat = GetRotation(controllerMatrix); - vr::HmdQuaternion_t handQuat = m_maintainPose.qRotation; - + isCalibrating_ = false; + // get the matrix that represents the position of the controller that we are shadowing + const vr::HmdMatrix34_t controllerMatrix = controllerPose.mDeviceToAbsoluteTracking; - //qC * qT = qH -> qC*qC^-1 * qT = qH * qC^-1 -> qT = qH * qC^-1 - vr::HmdQuaternion_t transformQuat = MultiplyQuaternion(QuatConjugate(controllerQuat), handQuat); - //m_poseConfiguration.angleOffsetQuaternion = transformQuat; - poseConfiguration.angleOffsetQuaternion.w = transformQuat.w; - poseConfiguration.angleOffsetQuaternion.x = transformQuat.x; - poseConfiguration.angleOffsetQuaternion.y = transformQuat.y; - poseConfiguration.angleOffsetQuaternion.z = transformQuat.z; + const vr::HmdQuaternion_t controllerQuat = GetRotation(controllerMatrix); + const vr::HmdQuaternion_t handQuat = maintainPose_.qRotation; - vr::HmdVector3_t differenceVector = { (float)(m_maintainPose.vecPosition[0] - controllerMatrix.m[0][3]), - (float)(m_maintainPose.vecPosition[1] - controllerMatrix.m[1][3]), - (float)(m_maintainPose.vecPosition[2] - controllerMatrix.m[2][3]) }; + // qC * qT = qH -> qC*qC^-1 * qT = qH * qC^-1 -> qT = qH * qC^-1 + const vr::HmdQuaternion_t transformQuat = MultiplyQuaternion(QuatConjugate(controllerQuat), handQuat); - vr::HmdQuaternion_t transformInverse = QuatConjugate(controllerQuat); - vr::HmdMatrix33_t transformMatrix = QuaternionToMatrix(transformInverse); - vr::HmdVector3_t transformVector = MultiplyMatrix(transformMatrix, differenceVector); + poseConfiguration.angleOffsetQuaternion.w = transformQuat.w; + poseConfiguration.angleOffsetQuaternion.x = transformQuat.x; + poseConfiguration.angleOffsetQuaternion.y = transformQuat.y; + poseConfiguration.angleOffsetQuaternion.z = transformQuat.z; - poseConfiguration.offsetVector = transformVector; + const vr::HmdVector3_t differenceVector = { + static_cast(maintainPose_.vecPosition[0] - controllerMatrix.m[0][3]), + static_cast(maintainPose_.vecPosition[1] - controllerMatrix.m[1][3]), + static_cast(maintainPose_.vecPosition[2] - controllerMatrix.m[2][3])}; - vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_position" : "left_x_offset_position", transformVector.v[0]); - vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_position" : "left_y_offset_position", transformVector.v[1]); - vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_position" : "left_z_offset_position", transformVector.v[2]); + const vr::HmdQuaternion_t transformInverse = QuatConjugate(controllerQuat); + const vr::HmdMatrix33_t transformMatrix = QuaternionToMatrix(transformInverse); + const vr::HmdVector3_t transformVector = MultiplyMatrix(transformMatrix, differenceVector); - vr::HmdVector3_t eulerOffset = QuaternionToEuler(transformQuat); + poseConfiguration.offsetVector = transformVector; - vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_degrees" : "left_x_offset_degrees", eulerOffset.v[0]); - vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_degrees" : "left_y_offset_degrees", eulerOffset.v[1]); - vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_degrees" : "left_z_offset_degrees", eulerOffset.v[2]); + vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_position" : "left_x_offset_position", transformVector.v[0]); + vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_position" : "left_y_offset_position", transformVector.v[1]); + vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_position" : "left_z_offset_position", transformVector.v[2]); - return poseConfiguration; -} + const vr::HmdVector3_t eulerOffset = QuaternionToEuler(transformQuat); -void Calibration::CancelCalibration() { m_isCalibrating = false; } + vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_degrees" : "left_x_offset_degrees", eulerOffset.v[0]); + vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_degrees" : "left_y_offset_degrees", eulerOffset.v[1]); + vr::VRSettings()->SetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_degrees" : "left_z_offset_degrees", eulerOffset.v[2]); -bool Calibration::isCalibrating() { - return m_isCalibrating; + return poseConfiguration; } -vr::DriverPose_t Calibration::GetMaintainPose() { - return m_maintainPose; +void Calibration::CancelCalibration(CalibrationMethod method) { + if (calibratingMethod_ == method) isCalibrating_ = false; } +bool Calibration::IsCalibrating() const { + return isCalibrating_; +} + +vr::DriverPose_t Calibration::GetMaintainPose() const { + return maintainPose_; +} diff --git a/src/Communication/BTSerialCommunicationManager.cpp b/src/Communication/BTSerialCommunicationManager.cpp index 4641173f..d08cab61 100644 --- a/src/Communication/BTSerialCommunicationManager.cpp +++ b/src/Communication/BTSerialCommunicationManager.cpp @@ -1,143 +1,138 @@ #include "Communication/BTSerialCommunicationManager.h" -#include +#include +#include -#include "Util/Windows.h" +#include -static const uint32_t c_listenerWaitTime = 1000; +#include "DriverLog.h" +#include "Util/Logic.h" +#include "Util/Windows.h" +BTSerialCommunicationManager::BTSerialCommunicationManager( + std::unique_ptr encodingManager, const VRBTSerialConfiguration configuration, const VRDeviceConfiguration& deviceConfiguration) + : CommunicationManager(std::move(encodingManager), deviceConfiguration), + btSerialConfiguration_(configuration), + isConnected_(false), + btClientSocket_(NULL) {} -BTSerialCommunicationManager::BTSerialCommunicationManager(const VRBTSerialConfiguration_t& configuration, std::unique_ptr encodingManager) - : m_btSerialConfiguration(configuration), - m_encodingManager(std::move(encodingManager)), - m_isConnected(false), - m_btClientSocket(NULL), - m_btSocketAddress(), - m_deviceBtAddress(NULL), - m_wcDeviceName(NULL){}; +bool BTSerialCommunicationManager::IsConnected() { + return isConnected_; +} bool BTSerialCommunicationManager::Connect() { // We're not yet connected - m_isConnected = false; + isConnected_ = false; - if (!GetPairedDeviceBtAddress() || !StartupWindowsSocket() || !ConnectToDevice()) { + BTH_ADDR deviceBtAddress; + if (!GetPairedDeviceBtAddress(&deviceBtAddress) || !StartupWindowsSocket() || !ConnectToDevice(deviceBtAddress)) { LogMessage("Failed to connect to device"); return false; } // If everything went fine we're connected - m_isConnected = true; + isConnected_ = true; LogMessage("Connected to bluetooth"); return true; } -void BTSerialCommunicationManager::BeginListener(const std::function& callback) { - m_threadActive = true; - m_serialThread = std::thread(&BTSerialCommunicationManager::ListenerThread, this, callback); -} - -void BTSerialCommunicationManager::ListenerThread(const std::function& callback) { - WaitAttemptConnection(); - - while (m_threadActive) { - std::string receivedString; - bool readSuccessful = ReceiveNextPacket(receivedString); - if (readSuccessful) { - try { - VRCommData_t commData = m_encodingManager->Decode(receivedString); - callback(commData); - SendMessageToDevice(); - continue; - } catch (const std::invalid_argument& ia) { - DriverLog("Received error from encoding manager: %s", ia.what()); - } - } - LogMessage("Detected device error. Disconnecting socket and attempting reconnection...."); - if (DisconnectFromDevice()) { - WaitAttemptConnection(); - LogMessage("Successfully reconnected to device."); - continue; - } - LogMessage("Could not disconnect. Closing listener..."); - Disconnect(); +bool BTSerialCommunicationManager::DisconnectFromDevice() { + if (shutdown(btClientSocket_, 2) == SOCKET_ERROR) { + LogMessage("Could not disconnect socket from bluetooth device"); + return false; } + + isConnected_ = false; + LogMessage("Disconnected from socket successfully"); + return true; } bool BTSerialCommunicationManager::ReceiveNextPacket(std::string& buff) { char nextChar = 0; do { - int recieveResult = recv(m_btClientSocket, &nextChar, 1, 0); - if (recieveResult <= 0) continue; + const int receiveResult = recv(btClientSocket_, &nextChar, 1, 0); + if (receiveResult <= 0 || nextChar == '\n') continue; buff += nextChar; - } while (nextChar != '\n' || buff.length() < 1); + } while (threadActive_ && (nextChar != '\n' || buff.length() < 1)); + + if (!threadActive_) return false; return true; } -void BTSerialCommunicationManager::QueueSend(const VRFFBData_t& data) { - std::lock_guard lock(m_writeMutex); +bool BTSerialCommunicationManager::SendMessageToDevice() { + std::lock_guard lock(writeMutex_); - m_writeString = m_encodingManager->Encode(data); -} + const char* message = writeString_.c_str(); -void BTSerialCommunicationManager::Disconnect() { - if (m_isConnected) { - if (m_threadActive) { - m_threadActive = false; - m_serialThread.join(); - } - DisconnectFromDevice(); - } -} + if (!Retry([&]() { return send(btClientSocket_, message, static_cast(writeString_.length()), 0) != SOCKET_ERROR; }, 5, 10)) { + LogError("Sending to Bluetooth Device failed... closing"); -bool BTSerialCommunicationManager::DisconnectFromDevice() { - if (shutdown(m_btClientSocket, 2) == SOCKET_ERROR) { - LogMessage("Could not disconnect socket from bluetooth device"); - return false; + closesocket(btClientSocket_); + WSACleanup(); } - m_isConnected = false; - LogMessage("Disconnected from socket successfully"); return true; } -bool BTSerialCommunicationManager::IsConnected() { return m_isConnected; } +bool BTSerialCommunicationManager::ConnectToDevice(const BTH_ADDR& deviceBtAddress) { + btClientSocket_ = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); // initialize BT windows socket + + SOCKADDR_BTH btSocketAddress{}; + btSocketAddress.addressFamily = AF_BTH; + btSocketAddress.serviceClassId = RFCOMM_PROTOCOL_UUID; + btSocketAddress.port = 0; // port needs to be 0 if the remote device is a client. See references. + btSocketAddress.btAddr = deviceBtAddress; // this is the BT address of the remote device. + + if (connect(btClientSocket_, reinterpret_cast(&btSocketAddress), sizeof btSocketAddress) != 0) // connect to the BT device. + { + LogError("Could not connect socket to Bluetooth Device"); + return false; + } -void BTSerialCommunicationManager::WaitAttemptConnection() { - while (m_threadActive && !IsConnected() && !Connect()) { - std::this_thread::sleep_for(std::chrono::milliseconds(c_listenerWaitTime)); + unsigned long nonBlockingMode = 1; + // set the socket to be non-blocking, meaning it will return right away when sending/receiving + if (ioctlsocket(btClientSocket_, FIONBIO, &nonBlockingMode) != 0) { + LogError("Could not set socket to be non-blocking"); + return false; } + + return true; } -bool BTSerialCommunicationManager::GetPairedDeviceBtAddress() { - BLUETOOTH_DEVICE_SEARCH_PARAMS btDeviceSearchParameters = { +bool BTSerialCommunicationManager::GetPairedDeviceBtAddress(BTH_ADDR* deviceBtAddress) { + constexpr BLUETOOTH_DEVICE_SEARCH_PARAMS btDeviceSearchParameters = { sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), // size of object 1, // return authenticated devices 0, // return remembered devices 1, // return unknown devices 1, // return connected devices - 1, // issue inquery - 2, // timeout multipler. Multiply this value by 1.28 seconds to get timeout. - NULL // radio handler + 1, // issue in query + 2, // timeout multiplier. Multiply this value by 1.28 seconds to get timeout. + nullptr // radio handler }; - BLUETOOTH_DEVICE_INFO btDeviceInfo = {sizeof(BLUETOOTH_DEVICE_INFO), 0}; // default - HBLUETOOTH_DEVICE_FIND btDevice = NULL; - btDevice = BluetoothFindFirstDevice(&btDeviceSearchParameters, &btDeviceInfo); // returns first BT device connected to this machine - if (btDevice == NULL) { + + BLUETOOTH_DEVICE_INFO btDeviceInfo = {sizeof(BLUETOOTH_DEVICE_INFO), {0}}; // default + const HBLUETOOTH_DEVICE_FIND btDevice = + BluetoothFindFirstDevice(&btDeviceSearchParameters, &btDeviceInfo); // returns first BT device connected to this machine + + if (btDevice == nullptr) { LogMessage("Could not find any bluetooth devices"); + *deviceBtAddress = NULL; return false; } - do { - std::wstring thiswstring = std::wstring(m_btSerialConfiguration.name.begin(), m_btSerialConfiguration.name.end()); - m_wcDeviceName = (WCHAR*)(thiswstring.c_str()); - if (wcscmp(btDeviceInfo.szName, m_wcDeviceName) == 0) { + const auto thiswstring = std::wstring(btSerialConfiguration_.name.begin(), btSerialConfiguration_.name.end()); + const WCHAR* wcDeviceName = const_cast(thiswstring.c_str()); + + do { + if (wcscmp(btDeviceInfo.szName, wcDeviceName) == 0) { LogMessage("Bluetooth Device found"); if (btDeviceInfo.fAuthenticated) // I found that if fAuthenticated is true it means the device is paired. { LogMessage("Bluetooth Device is authenticated"); - m_deviceBtAddress = btDeviceInfo.Address.ullLong; + *deviceBtAddress = btDeviceInfo.Address.ullLong; return true; } else { LogMessage("This Bluetooth Device is not authenticated. Please pair with it first"); @@ -146,65 +141,28 @@ bool BTSerialCommunicationManager::GetPairedDeviceBtAddress() { } while (BluetoothFindNextDevice(btDevice, &btDeviceInfo)); // loop through remaining BT devices connected to this machine LogMessage("Could not find paired Bluetooth Device"); + *deviceBtAddress = NULL; return false; } bool BTSerialCommunicationManager::StartupWindowsSocket() { - WORD wVersionRequested; + constexpr WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; - wVersionRequested = MAKEWORD(2, 2); - int wsaStartupError = WSAStartup(wVersionRequested, &wsaData); // call this before using BT windows socket. - if (wsaStartupError != 0) { - LogMessage("WSA failed to startup"); - return false; - } - return true; -} - -bool BTSerialCommunicationManager::ConnectToDevice() { - m_btClientSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); // initialize BT windows socket - memset(&m_btSocketAddress, 0, sizeof(m_btSocketAddress)); - m_btSocketAddress.addressFamily = AF_BTH; - m_btSocketAddress.serviceClassId = RFCOMM_PROTOCOL_UUID; - m_btSocketAddress.port = 0; // port needs to be 0 if the remote device is a client. See references. - m_btSocketAddress.btAddr = m_deviceBtAddress; // this is the BT address of the remote device. - if (connect(m_btClientSocket, (SOCKADDR*)&m_btSocketAddress, sizeof(m_btSocketAddress)) != 0) // connect to the BT device. - { - LogError("Could not connect socket to Bluetooth Device"); - return false; - } - unsigned long nonBlockingMode = 1; - if (ioctlsocket(m_btClientSocket, FIONBIO, (unsigned long*)&nonBlockingMode) != 0) // set the socket to be non-blocking, meaning - { // it will return right away when sending/recieving - LogError("Could not set socket to be non-blocking"); + if (const int wsaStartupError = WSAStartup(wVersionRequested, &wsaData); wsaStartupError != 0) { + LogMessage("WSA failed to startup"); return false; } return true; } -bool BTSerialCommunicationManager::SendMessageToDevice() { - std::lock_guard lock(m_writeMutex); - const char* message = m_writeString.c_str(); - int sendResult = send(m_btClientSocket, message, (int)strlen(message), 0); // send your message to the BT device - if (sendResult == SOCKET_ERROR) { - LogError("Sending to Bluetooth Device failed"); - - closesocket(m_btClientSocket); - WSACleanup(); - - return false; - } - return true; -} - void BTSerialCommunicationManager::LogError(const char* message) { // message with port name and last error - DriverLog("%s (%s) - Error: %s", message, m_btSerialConfiguration.name.c_str(), GetLastErrorAsString().c_str()); + DriverLog("%s (%s) - Error: %s", message, btSerialConfiguration_.name.c_str(), GetLastErrorAsString().c_str()); } void BTSerialCommunicationManager::LogMessage(const char* message) { // message with port name - DriverLog("%s (%s)", message, m_btSerialConfiguration.name.c_str()); -} \ No newline at end of file + DriverLog("%s (%s)", message, btSerialConfiguration_.name.c_str()); +} diff --git a/src/Communication/CommunicationManager.cpp b/src/Communication/CommunicationManager.cpp new file mode 100644 index 00000000..4a3bae82 --- /dev/null +++ b/src/Communication/CommunicationManager.cpp @@ -0,0 +1,69 @@ +#include "Communication/CommunicationManager.h" + +#include + +#include "DeviceConfiguration.h" + +static const uint32_t c_listenerWaitTime = 1000; + +CommunicationManager::CommunicationManager(const VRDeviceConfiguration& deviceConfiguration) : CommunicationManager(nullptr, deviceConfiguration) {} + +CommunicationManager::CommunicationManager(std::unique_ptr encodingManager, const VRDeviceConfiguration& deviceConfiguration) + : encodingManager_(std::move(encodingManager)), deviceConfiguration_(deviceConfiguration), threadActive_(false) { + // initially no force feedback + QueueSend(VRFFBData(0, 0, 0, 0, 0)); +} + +void CommunicationManager::BeginListener(const std::function& callback) { + threadActive_ = true; + thread_ = std::thread(&CommunicationManager::ListenerThread, this, callback); +} + +void CommunicationManager::Disconnect() { + if (threadActive_.exchange(false)) thread_.join(); + + if (IsConnected()) DisconnectFromDevice(); +} + +void CommunicationManager::QueueSend(const VRFFBData& data) { + std::lock_guard lock(writeMutex_); + + if(encodingManager_ != nullptr) writeString_ = encodingManager_->Encode(data); +} + +void CommunicationManager::ListenerThread(const std::function& callback) { + WaitAttemptConnection(); + + while (threadActive_) { + if (std::string receivedString; ReceiveNextPacket(receivedString)) { + try { + const VRInputData commData = encodingManager_->Decode(receivedString); + callback(commData); + + if (deviceConfiguration_.feedbackEnabled) { + SendMessageToDevice(); + } + + continue; + } catch (const std::invalid_argument& ia) { + LogMessage((std::string("Received error from encoding manager: ") + ia.what()).c_str()); + } + } + + LogMessage("Detected device error. Disconnecting socket and attempting reconnection..."); + + if (DisconnectFromDevice()) { + WaitAttemptConnection(); + LogMessage("Successfully reconnected to device."); + } else { + LogMessage("Could not disconnect. Closing listener..."); + Disconnect(); + } + } +} + +void CommunicationManager::WaitAttemptConnection() { + while (threadActive_ && !IsConnected() && !Connect()) { + std::this_thread::sleep_for(std::chrono::milliseconds(c_listenerWaitTime)); + } +} diff --git a/src/Communication/NamedPipeCommunicationManager.cpp b/src/Communication/NamedPipeCommunicationManager.cpp new file mode 100644 index 00000000..8ba0bc16 --- /dev/null +++ b/src/Communication/NamedPipeCommunicationManager.cpp @@ -0,0 +1,42 @@ +#include "Communication/NamedPipeCommunicationManager.h" + +#include + +NamedPipeCommunicationManager::NamedPipeCommunicationManager( + VRNamedPipeInputConfiguration configuration, const VRDeviceConfiguration& deviceConfiguration) + : CommunicationManager(deviceConfiguration), isConnected_(false), configuration_(std::move(configuration)){}; + +bool NamedPipeCommunicationManager::Connect() { + namedPipeListener_ = std::make_unique>(configuration_.pipeName); + return true; +} + +void NamedPipeCommunicationManager::BeginListener(const std::function& callback) { + callback_ = callback; + + if (!Connect()) { + DriverLog("Unable to connect to named pipe."); + return; + } + + namedPipeListener_->StartListening([&](const VRInputData* data) { callback_(*data); }); +} + +bool NamedPipeCommunicationManager::DisconnectFromDevice() { + namedPipeListener_->StopListening(); + return true; +} + +bool NamedPipeCommunicationManager::IsConnected() { + return namedPipeListener_->IsConnected(); +} + +void NamedPipeCommunicationManager::LogError(const char* message) { + // message with port name and last error + DriverLog("%s (%s) - Error: %s", message, configuration_.pipeName.c_str(), GetLastErrorAsString().c_str()); +} + +void NamedPipeCommunicationManager::LogMessage(const char* message) { + // message with port name + DriverLog("%s (%s)", message, configuration_.pipeName.c_str()); +} \ No newline at end of file diff --git a/src/Communication/SerialCommunicationManager.cpp b/src/Communication/SerialCommunicationManager.cpp index 1e17e7ef..68b4bd26 100644 --- a/src/Communication/SerialCommunicationManager.cpp +++ b/src/Communication/SerialCommunicationManager.cpp @@ -1,138 +1,117 @@ #include "Communication/SerialCommunicationManager.h" +#include + #include "DriverLog.h" #include "Util/Windows.h" -#include +SerialCommunicationManager::SerialCommunicationManager( + std::unique_ptr encodingManager, VRSerialConfiguration configuration, const VRDeviceConfiguration& deviceConfiguration) + : CommunicationManager(std::move(encodingManager), deviceConfiguration), + serialConfiguration_(std::move(configuration)), + isConnected_(false), + hSerial_(nullptr) {} -static const uint32_t c_listenerWaitTime = 1000; +bool SerialCommunicationManager::IsConnected() { + return isConnected_; +}; bool SerialCommunicationManager::Connect() { + LogMessage("Attempting connection to device"); // We're not yet connected - m_isConnected = false; + isConnected_ = false; // Try to connect to the given port throuh CreateFile - m_hSerial = CreateFile(m_serialConfiguration.port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (this->m_hSerial == INVALID_HANDLE_VALUE) { + hSerial_ = CreateFile(serialConfiguration_.port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hSerial_ == INVALID_HANDLE_VALUE) { LogError("Received error connecting to port"); return false; } // If connected we try to set the comm parameters DCB dcbSerialParams = {0}; - - if (!GetCommState(m_hSerial, &dcbSerialParams)) { + if (!GetCommState(hSerial_, &dcbSerialParams)) { LogError("Failed to get current port parameters"); return false; } - // Define serial connection parameters for the arduino board - dcbSerialParams.BaudRate = m_serialConfiguration.baudRate; + // Define serial connection parameters for the Arduino board + dcbSerialParams.BaudRate = serialConfiguration_.baudRate; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; - - // reset upon establishing a connection - dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; + dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; // reset upon establishing a connection // set the parameters and check for their proper application - if (!SetCommState(m_hSerial, &dcbSerialParams)) { + if (!SetCommState(hSerial_, &dcbSerialParams)) { LogError("Failed to set serial parameters"); return false; } // If everything went fine we're connected - m_isConnected = true; + isConnected_ = true; PurgeBuffer(); + LogMessage("Successfully connected to device"); + return true; } -void SerialCommunicationManager::WaitAttemptConnection() { - while (m_threadActive && !IsConnected() && !Connect()) { - std::this_thread::sleep_for(std::chrono::milliseconds(c_listenerWaitTime)); +bool SerialCommunicationManager::DisconnectFromDevice() { + if (!CloseHandle(hSerial_)) { + LogError("Error disconnecting from device"); + return false; } -} -void SerialCommunicationManager::BeginListener(const std::function& callback) { - m_threadActive = true; - m_serialThread = std::thread(&SerialCommunicationManager::ListenerThread, this, callback); -} - -void SerialCommunicationManager::ListenerThread(const std::function& callback) { - WaitAttemptConnection(); - - while (m_threadActive) { - std::string receivedString; - bool readSuccessful = ReceiveNextPacket(receivedString); - - if (readSuccessful) { - try { - VRCommData_t commData = m_encodingManager->Decode(receivedString); - callback(commData); - Write(); - continue; - } - catch (const std::invalid_argument& ia) { - LogMessage((std::string("Received error from encoding manager: ") + ia.what()).c_str()); - } - } - LogMessage("Detected device error. Disconnecting device and attempting reconnection"); - if (DisconnectFromDevice()) { - WaitAttemptConnection(); - LogMessage("Sucessfully reconnected to device"); - continue; - } - - LogMessage("Could not connect to device. Closing listener"); - Disconnect(); - } + isConnected_ = false; + LogMessage("Successfully disconnected from device"); + return true; } bool SerialCommunicationManager::ReceiveNextPacket(std::string& buff) { - DWORD dwCommEvent = 0; - DWORD dwRead = 0; - - if (!SetCommMask(m_hSerial, EV_RXCHAR)) { + if (!SetCommMask(hSerial_, EV_RXCHAR)) { LogError("Error setting comm mask"); return false; } - char nextChar = 0; + DWORD dwCommEvent = 0; + do { + if (!WaitCommEvent(hSerial_, &dwCommEvent, nullptr)) { + LogError("Error waiting for event"); + return false; + } + } while (threadActive_ && (dwCommEvent & EV_RXCHAR) != EV_RXCHAR); - if (!WaitCommEvent(m_hSerial, &dwCommEvent, NULL)) { - LogError("Error waiting for event"); - return false; - } + if (!threadActive_) return false; + char nextChar = 0; do { - if (!ReadFile(m_hSerial, &nextChar, 1, &dwRead, NULL)) { + DWORD dwRead = 0; + if (!ReadFile(hSerial_, &nextChar, 1, &dwRead, nullptr)) { LogError("Error reading from file"); return false; } + if (dwRead <= 0 || nextChar == '\n') continue; buff += nextChar; - } while (nextChar != '\n'); - - return true; -} + } while ((nextChar != '\n' || buff.length() < 1) && threadActive_); -void SerialCommunicationManager::QueueSend(const VRFFBData_t& data) { - std::lock_guard lock(m_writeMutex); + // If the glove firmware sends data more often than we poll for it then the buffer + // will become saturated and block future reads. We've got the data we need so purge + // anything else left in the buffer. There should be more data ready for us in the + // buffer by the next time we poll for it. + PurgeBuffer(); - m_writeString = m_encodingManager->Encode(data); + return true; } -bool SerialCommunicationManager::Write() { - std::lock_guard lock(m_writeMutex); - - const char* buf = m_writeString.c_str(); +bool SerialCommunicationManager::SendMessageToDevice() { + std::lock_guard lock(writeMutex_); - DWORD bytesSend; - - if (!WriteFile(this->m_hSerial, (void*)buf, (DWORD)strlen(buf), &bytesSend, 0)) { + const char* buf = writeString_.c_str(); + DWORD bytesSent; + if (!WriteFile(hSerial_, buf, static_cast(writeString_.length()), &bytesSent, nullptr) || bytesSent < writeString_.length()) { LogError("Error writing to port"); return false; } @@ -140,37 +119,16 @@ bool SerialCommunicationManager::Write() { return true; } -bool SerialCommunicationManager::PurgeBuffer() { return PurgeComm(m_hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR); } - -void SerialCommunicationManager::Disconnect() { - if (m_isConnected) { - if (m_threadActive) { - m_threadActive = false; - m_serialThread.join(); - } - DisconnectFromDevice(); - } +bool SerialCommunicationManager::PurgeBuffer() const { + return PurgeComm(hSerial_, PURGE_RXCLEAR | PURGE_TXCLEAR); } -bool SerialCommunicationManager::DisconnectFromDevice() { - if (!CloseHandle(m_hSerial)) { - LogError("Error disconnecting from device"); - return false; - } - - m_isConnected = false; - LogMessage("Succesfully disconnected from device"); - return true; -} - -bool SerialCommunicationManager::IsConnected() { return m_isConnected; }; - void SerialCommunicationManager::LogError(const char* message) { // message with port name and last error - DriverLog("%s (%s) - Error: %s", message, m_serialConfiguration.port.c_str(), GetLastErrorAsString().c_str()); + DriverLog("%s (%s) - Error: %s", message, serialConfiguration_.port.c_str(), GetLastErrorAsString().c_str()); } void SerialCommunicationManager::LogMessage(const char* message) { // message with port name - DriverLog("%s (%s)", message, m_serialConfiguration.port.c_str()); -} \ No newline at end of file + DriverLog("%s (%s)", message, serialConfiguration_.port.c_str()); +} diff --git a/src/ControllerDiscovery.cpp b/src/ControllerDiscovery.cpp index 0a7d7ae5..a5708533 100644 --- a/src/ControllerDiscovery.cpp +++ b/src/ControllerDiscovery.cpp @@ -1,21 +1,17 @@ #include "ControllerDiscovery.h" -#include "DriverLog.h" +ControllerDiscovery::ControllerDiscovery(vr::ETrackedControllerRole role, std::function callback) + : role_(role), callback_(std::move(callback)) { + std::string pipeName = + R"(\\.\pipe\vrapplication\discovery\)" + std::string(role == vr::ETrackedControllerRole::TrackedControllerRole_RightHand ? "right" : "left"); -ControllerDiscovery::ControllerDiscovery(vr::ETrackedControllerRole role, std::function callback) - : m_role(role), m_callback(std::move(callback)) { - - std::string pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\" + std::string(role == vr::ETrackedControllerRole::TrackedControllerRole_RightHand ? "right" : "left"); - - m_pipe = std::make_unique(pipeName, sizeof(ControllerDiscoveryPipeData_t)); + pipe_ = std::make_unique>(pipeName); }; void ControllerDiscovery::Start() { - m_pipe->Start([&](LPVOID data) { - ControllerDiscoveryPipeData_t *controllerPipeData = (ControllerDiscoveryPipeData_t *)data; - - m_callback(*controllerPipeData); - }); + pipe_->StartListening([&](const ControllerDiscoveryPipeData* data) { callback_(*data); }); }; -void ControllerDiscovery::Stop() { m_pipe->Stop(); }; \ No newline at end of file +void ControllerDiscovery::Stop() const { + pipe_->StopListening(); +}; \ No newline at end of file diff --git a/src/ControllerPose.cpp b/src/ControllerPose.cpp index 0598ce91..3d58ff84 100644 --- a/src/ControllerPose.cpp +++ b/src/ControllerPose.cpp @@ -1,86 +1,94 @@ #include "ControllerPose.h" #include "DriverLog.h" -#include "Quaternion.h" +#include "Util/Quaternion.h" -struct CalibrationDataIn { - uint8_t start; -}; +ControllerPose::ControllerPose( + vr::ETrackedControllerRole shadowDeviceOfRole, std::string thisDeviceManufacturer, VRPoseConfiguration poseConfiguration) + : poseConfiguration_(poseConfiguration), shadowDeviceOfRole_(shadowDeviceOfRole), thisDeviceManufacturer_(std::move(thisDeviceManufacturer)) { + calibrationPipe_ = std::make_unique>( + R"(\\.\pipe\vrapplication\functions\autocalibrate\)" + + std::string(shadowDeviceOfRole == vr::ETrackedControllerRole::TrackedControllerRole_RightHand ? "right" : "left")); -ControllerPose::ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, std::string thisDeviceManufacturer, VRPoseConfiguration_t poseConfiguration) - : m_shadowDeviceOfRole(shadowDeviceOfRole), m_thisDeviceManufacturer(std::move(thisDeviceManufacturer)), m_poseConfiguration(poseConfiguration) { - m_calibrationPipe = - std::make_unique("\\\\.\\pipe\\vrapplication\\functions\\autocalibrate\\" + - std::string(shadowDeviceOfRole == vr::ETrackedControllerRole::TrackedControllerRole_RightHand ? "right" : "left"), - sizeof(CalibrationDataIn)); - - m_calibrationPipe->Start([&](LPVOID data) { - CalibrationDataIn *calibrationData = (CalibrationDataIn *)data; - - if (calibrationData->start) { + calibrationPipe_->StartListening([&](const CalibrationDataIn* data) { + if (data->start) { DriverLog("Starting calibration via external application"); - StartCalibration(); + StartCalibration(CalibrationMethod::Ui); } else { DriverLog("Stopping calibration via external application"); - CompleteCalibration(); + CompleteCalibration(CalibrationMethod::Ui); } }); - if (m_poseConfiguration.controllerOverrideEnabled) { - m_shadowControllerId = m_poseConfiguration.controllerIdOverride; + if (poseConfiguration_.controllerOverrideEnabled) { + shadowControllerId_ = poseConfiguration_.controllerIdOverride; } else { - m_controllerDiscoverer = std::make_unique(shadowDeviceOfRole, [&](ControllerDiscoveryPipeData_t data) { - m_shadowControllerId = data.controllerId; + controllerDiscoverer_ = std::make_unique(shadowDeviceOfRole, [&](const ControllerDiscoveryPipeData data) { + shadowControllerId_ = data.controllerId; DriverLog("Received controller id from overlay: %i", data.controllerId); }); - m_controllerDiscoverer->Start(); + controllerDiscoverer_->Start(); } - m_calibration = std::make_unique(); + calibration_ = std::make_unique(); +} + +ControllerPose::~ControllerPose() { + calibrationPipe_->StopListening(); + if (controllerDiscoverer_) controllerDiscoverer_->Stop(); } -vr::TrackedDevicePose_t ControllerPose::GetControllerPose() { +vr::TrackedDevicePose_t ControllerPose::GetControllerPose() const { vr::TrackedDevicePose_t trackedDevicePoses[vr::k_unMaxTrackedDeviceCount]; vr::VRServerDriverHost()->GetRawTrackedDevicePoses(0, trackedDevicePoses, vr::k_unMaxTrackedDeviceCount); - return trackedDevicePoses[m_shadowControllerId]; + return trackedDevicePoses[shadowControllerId_]; } -vr::DriverPose_t ControllerPose::UpdatePose() { - if (m_calibration->isCalibrating()) return m_calibration->GetMaintainPose(); +vr::DriverPose_t ControllerPose::UpdatePose() const { + if (calibration_->IsCalibrating()) return calibration_->GetMaintainPose(); vr::DriverPose_t newPose = {0}; newPose.qWorldFromDriverRotation.w = 1; newPose.qDriverFromHeadRotation.w = 1; - if (m_shadowControllerId != vr::k_unTrackedDeviceIndexInvalid) { - vr::TrackedDevicePose_t controllerPose = GetControllerPose(); - + if (shadowControllerId_ != vr::k_unTrackedDeviceIndexInvalid) { + const vr::TrackedDevicePose_t controllerPose = GetControllerPose(); if (controllerPose.bPoseIsValid) { // get the matrix that represents the position of the controller that we are shadowing - vr::HmdMatrix34_t controllerMatrix = controllerPose.mDeviceToAbsoluteTracking; + const vr::HmdMatrix34_t controllerMatrix = controllerPose.mDeviceToAbsoluteTracking; // get only the rotation (3x3 matrix), as the 3x4 matrix also includes position - vr::HmdMatrix33_t controllerRotationMatrix = GetRotationMatrix(controllerMatrix); + const vr::HmdMatrix33_t controllerRotationMatrix = GetRotationMatrix(controllerMatrix); + const vr::HmdQuaternion_t controllerRotation = GetRotation(controllerMatrix); - // multiply the rotation matrix by the offset vector set that is the offset of the controller - // relative to the hand - vr::HmdVector3_t vectorOffset = MultiplyMatrix(controllerRotationMatrix, m_poseConfiguration.offsetVector); + const vr::HmdVector3_t vectorOffset = MultiplyMatrix(controllerRotationMatrix, poseConfiguration_.offsetVector); // combine these positions to get the resultant position - vr::HmdVector3_t newControllerPosition = CombinePosition(controllerMatrix, vectorOffset); + const vr::HmdVector3_t newControllerPosition = CombinePosition(controllerMatrix, vectorOffset); newPose.vecPosition[0] = newControllerPosition.v[0]; newPose.vecPosition[1] = newControllerPosition.v[1]; newPose.vecPosition[2] = newControllerPosition.v[2]; - // Multiply rotation quaternions together, as the controller may be rotated relative to the - // hand - newPose.qRotation = MultiplyQuaternion(GetRotation(controllerMatrix), m_poseConfiguration.angleOffsetQuaternion); + newPose.qRotation = MultiplyQuaternion(controllerRotation, poseConfiguration_.angleOffsetQuaternion); + + // Angular velocity + // Converted from euler angle provided in world space to euler angle in object space + vr::HmdVector3_t angularVelocityWorld = controllerPose.vAngularVelocity; + angularVelocityWorld.v[0] /= 100.0; + angularVelocityWorld.v[1] /= 100.0; + angularVelocityWorld.v[2] /= 100.0; + + vr::HmdQuaternion_t qAngularVelocityWorld = EulerToQuaternion(angularVelocityWorld.v[2], angularVelocityWorld.v[1], angularVelocityWorld.v[0]); - // Copy other values from the controller that we want for this device - newPose.vecAngularVelocity[0] = controllerPose.vAngularVelocity.v[0]; - newPose.vecAngularVelocity[1] = controllerPose.vAngularVelocity.v[1]; - newPose.vecAngularVelocity[2] = controllerPose.vAngularVelocity.v[2]; + vr::HmdQuaternion_t qAngularVelocityObject = + MultiplyQuaternion(MultiplyQuaternion(QuatConjugate(newPose.qRotation), qAngularVelocityWorld), newPose.qRotation); + + vr::HmdVector3_t angularVelocityObject = QuaternionToEuler(qAngularVelocityObject); + + newPose.vecAngularVelocity[0] = angularVelocityObject.v[0] * (double)100.0; + newPose.vecAngularVelocity[1] = angularVelocityObject.v[1] * (double)100.0; + newPose.vecAngularVelocity[2] = angularVelocityObject.v[2] * (double)100.0; newPose.vecVelocity[0] = controllerPose.vVelocity.v[0]; newPose.vecVelocity[1] = controllerPose.vVelocity.v[1]; @@ -91,7 +99,7 @@ vr::DriverPose_t ControllerPose::UpdatePose() { newPose.result = vr::TrackingResult_Running_OK; - newPose.poseTimeOffset = m_poseConfiguration.poseTimeOffset; + newPose.poseTimeOffset = poseConfiguration_.poseTimeOffset; } else { newPose.poseIsValid = false; newPose.deviceIsConnected = true; @@ -106,19 +114,27 @@ vr::DriverPose_t ControllerPose::UpdatePose() { return newPose; } -void ControllerPose::StartCalibration() { m_calibration->StartCalibration(UpdatePose()); } +void ControllerPose::StartCalibration(const CalibrationMethod method) const { + calibration_->StartCalibration(UpdatePose(), method); +} -void ControllerPose::CompleteCalibration() { - if (m_shadowControllerId == vr::k_unTrackedDeviceIndexInvalid) { +void ControllerPose::CompleteCalibration(const CalibrationMethod method) { + if (shadowControllerId_ == vr::k_unTrackedDeviceIndexInvalid) { DriverLog("Index invalid"); - CancelCalibration(); + CancelCalibration(method); return; } - m_poseConfiguration = m_calibration->CompleteCalibration(GetControllerPose(), m_poseConfiguration, isRightHand()); + poseConfiguration_ = calibration_->CompleteCalibration(GetControllerPose(), poseConfiguration_, IsRightHand(), method); } -void ControllerPose::CancelCalibration() { m_calibration->CancelCalibration(); } +void ControllerPose::CancelCalibration(const CalibrationMethod method) const { + calibration_->CancelCalibration(method); +} -bool ControllerPose::isCalibrating() { return m_calibration->isCalibrating(); } +bool ControllerPose::IsCalibrating() const { + return calibration_->IsCalibrating(); +} -bool ControllerPose::isRightHand() { return m_shadowDeviceOfRole == vr::TrackedControllerRole_RightHand; } \ No newline at end of file +bool ControllerPose::IsRightHand() const { + return shadowDeviceOfRole_ == vr::TrackedControllerRole_RightHand; +} diff --git a/src/DeviceConfiguration.cpp b/src/DeviceConfiguration.cpp index 2555cc68..47bc289d 100644 --- a/src/DeviceConfiguration.cpp +++ b/src/DeviceConfiguration.cpp @@ -5,4 +5,8 @@ const char* c_driverSettingsSection = "driver_openglove"; const char* c_serialCommunicationSettingsSection = "communication_serial"; const char* c_btserialCommunicationSettingsSection = "communication_btserial"; const char* c_knuckleDeviceSettingsSection = "device_knuckles"; -const char* c_lucidGloveDeviceSettingsSection = "device_lucidgloves"; \ No newline at end of file +const char* c_lucidGloveDeviceSettingsSection = "device_lucidgloves"; +const char* c_alphaEncodingSettingsSection = "encoding_alpha"; +const char* c_legacyEncodingSettingsSection = "encoding_legacy"; + +const char* c_deviceDriverManufacturer = "LucidVR"; diff --git a/src/DeviceDriver/DeviceDriver.cpp b/src/DeviceDriver/DeviceDriver.cpp new file mode 100644 index 00000000..39a2e478 --- /dev/null +++ b/src/DeviceDriver/DeviceDriver.cpp @@ -0,0 +1,125 @@ +#include "DeviceDriver/DeviceDriver.h" + +#include + +#include "DriverLog.h" + +DeviceDriver::DeviceDriver( + std::unique_ptr communicationManager, + std::shared_ptr boneAnimator, + std::string serialNumber, + const VRDeviceConfiguration configuration) + : communicationManager_(std::move(communicationManager)), + boneAnimator_(std::move(boneAnimator)), + configuration_(configuration), + serialNumber_(std::move(serialNumber)), + skeletalComponentHandle_(), + handTransforms_(), + hasActivated_(false), + driverId_(vr::k_unTrackedDeviceIndexInvalid) { + // copy a default bone transform to our hand transform for use in finger positioning later + std::copy( + std::begin(IsRightHand() ? rightOpenPose : leftOpenPose), std::end(IsRightHand() ? rightOpenPose : leftOpenPose), std::begin(handTransforms_)); +} + +vr::EVRInitError DeviceDriver::Activate(uint32_t unObjectId) { + driverId_ = unObjectId; + controllerPose_ = std::make_unique(configuration_.role, std::string(c_deviceDriverManufacturer), configuration_.poseConfiguration); + + vr::PropertyContainerHandle_t props = vr::VRProperties()->TrackedDeviceToPropertyContainer( + driverId_); // this gets a container object where you store all the information about your driver + + SetupProps(props); + + if (const vr::EVRInputError error = vr::VRDriverInput()->CreateSkeletonComponent( + props, + IsRightHand() ? "/input/skeleton/right" : "/input/skeleton/left", + IsRightHand() ? "/skeleton/hand/right" : "/skeleton/hand/left", + "/pose/raw", + vr::VRSkeletalTracking_Partial, + handTransforms_, + NUM_BONES, + &skeletalComponentHandle_); + error != vr::VRInputError_None) { + DebugDriverLog("CreateSkeletonComponent failed. Error: %s\n", error); + } + + StartDevice(); + + hasActivated_ = true; + + return vr::VRInitError_None; +} + +void DeviceDriver::Deactivate() { + if (hasActivated_) { + StoppingDevice(); + communicationManager_->Disconnect(); + driverId_ = vr::k_unTrackedDeviceIndexInvalid; + hasActivated_ = false; + } +} + +void DeviceDriver::DebugRequest(const char* pchRequest, char* pchResponseBuffer, const uint32_t unResponseBufferSize) { + if (unResponseBufferSize >= 1) pchResponseBuffer[0] = 0; +} + +void DeviceDriver::EnterStandby() {} + +void* DeviceDriver::GetComponent(const char* pchComponentNameAndVersion) { + return nullptr; +} + +vr::DriverPose_t DeviceDriver::GetPose() { + if (hasActivated_) return controllerPose_->UpdatePose(); + + return vr::DriverPose_t{0}; +} + +std::string DeviceDriver::GetSerialNumber() { + return serialNumber_; +} + +bool DeviceDriver::IsActive() { + return hasActivated_; +} + +void DeviceDriver::RunFrame() { + if (hasActivated_) { + vr::VRServerDriverHost()->TrackedDevicePoseUpdated(driverId_, controllerPose_->UpdatePose(), sizeof(vr::DriverPose_t)); + } +} + +bool DeviceDriver::IsRightHand() const { + return configuration_.role == vr::TrackedControllerRole_RightHand; +} + +void DeviceDriver::StartDevice() { + StartingDevice(); + + vr::VRDriverInput()->UpdateSkeletonComponent( + skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithoutController, IsRightHand() ? rightOpenPose : leftOpenPose, NUM_BONES); + vr::VRDriverInput()->UpdateSkeletonComponent( + skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithController, IsRightHand() ? rightOpenPose : leftOpenPose, NUM_BONES); + + communicationManager_->BeginListener([&](VRInputData data) { + try { + boneAnimator_->ComputeSkeletonTransforms(handTransforms_, data.flexion, IsRightHand()); + vr::VRDriverInput()->UpdateSkeletonComponent(skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithoutController, handTransforms_, NUM_BONES); + vr::VRDriverInput()->UpdateSkeletonComponent(skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithController, handTransforms_, NUM_BONES); + + HandleInput(data); + + if (configuration_.poseConfiguration.calibrationButtonEnabled) { + if (data.calibrate) { + if (!controllerPose_->IsCalibrating()) controllerPose_->StartCalibration(CalibrationMethod::Hardware); + } else { + if (controllerPose_->IsCalibrating()) controllerPose_->CompleteCalibration(CalibrationMethod::Hardware); + } + } + + } catch (const std::exception&) { + DebugDriverLog("Exception caught while parsing comm data"); + } + }); +} diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index 942f30bb..4c637e8b 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -2,65 +2,51 @@ #include -#include "DriverLog.h" - -static const char* c_deviceManufacturer = "LucidVR"; - -enum ComponentIndex : int { - SYSTEM_CLICK, - SYSTEM_TOUCH, - TRIGGER_CLICK, - TRIGGER_VALUE, - TRACKPAD_X, - TRACKPAD_Y, - TRACKPAD_TOUCH, - TRACKPAD_FORCE, - GRIP_TOUCH, - GRIP_FORCE, - GRIP_VALUE, - THUMBSTICK_CLICK, - THUMBSTICK_TOUCH, - THUMBSTICK_X, - THUMBSTICK_Y, - A_CLICK, - A_TOUCH, - B_CLICK, - B_TOUCH, - FINGER_INDEX, - FINGER_MIDDLE, - FINGER_RING, - FINGER_PINKY -}; - -KnuckleDeviceDriver::KnuckleDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, std::string serialNumber, - std::shared_ptr boneAnimator) - : m_configuration(configuration), - m_communicationManager(std::move(communicationManager)), - m_serialNumber(std::move(serialNumber)), - m_boneAnimator(std::move(boneAnimator)), - m_driverId(-1), - m_hasActivated(false) { - // copy a default bone transform to our hand transform for use in finger positioning later - std::copy(std::begin(m_configuration.role == vr::TrackedControllerRole_RightHand ? rightOpenPose : leftOpenPose), - std::end(m_configuration.role == vr::TrackedControllerRole_RightHand ? rightOpenPose : leftOpenPose), std::begin(m_handTransforms)); +KnuckleDeviceDriver::KnuckleDeviceDriver( + std::unique_ptr communicationManager, + std::shared_ptr boneAnimator, + std::string serialNumber, + bool approximateThumb, + const VRDeviceConfiguration configuration) + : DeviceDriver(std::move(communicationManager), std::move(boneAnimator), std::move(serialNumber), configuration), + inputComponentHandles_(), + haptic_(), approximateThumb_(approximateThumb){} + +void KnuckleDeviceDriver::HandleInput(const VRInputData data) { + // clang-format off + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickX)], data.joyX, 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickY)], data.joyY, 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickClick)], data.joyButton, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickTouch)], data.joyButton, 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TriggerClick)], data.trgButton, 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TriggerValue)], data.flexion[1], 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::AClick)], data.aButton, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ATouch)], data.aButton || (approximateThumb_ && data.flexion[0] > 0.6), 0); //Thumb approximation + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::BClick)], data.bButton, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::BTouch)], data.bButton, 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::GripForce)], data.grab, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::GripTouch)], data.grab, 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::GripValue)], data.grab, 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::SystemClick)], data.menu, 0); + + // We don't have a thumb on the index + // vr::VRDriverInput()->UpdateScalarComponent(_inputComponentHandles[(int)KnuckleDeviceComponentIndex::THUMB], data.flexion[0], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerIndex)], data.flexion[1], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerMiddle)], data.flexion[2], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerRing)], data.flexion[3], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerPinky)], data.flexion[4], 0); + // clang-format on } -bool KnuckleDeviceDriver::IsRightHand() const { return m_configuration.role == vr::TrackedControllerRole_RightHand; } - -std::string KnuckleDeviceDriver::GetSerialNumber() { return m_serialNumber; } - -bool KnuckleDeviceDriver::IsActive() { return m_hasActivated; } - -vr::EVRInitError KnuckleDeviceDriver::Activate(uint32_t unObjectId) { - const bool isRightHand = IsRightHand(); - - m_driverId = unObjectId; - m_controllerPose = std::make_unique(m_configuration.role, std::string(c_deviceManufacturer), m_configuration.poseConfiguration); - - vr::PropertyContainerHandle_t props = - vr::VRProperties()->TrackedDeviceToPropertyContainer(m_driverId); // this gets a container object where you store all the information about your driver - - vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerHandSelectionPriority_Int32, (int32_t)2147483647); +void KnuckleDeviceDriver::SetupProps(vr::PropertyContainerHandle_t& props) { + // clang-format off + vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerHandSelectionPriority_Int32, 2147483647); vr::VRProperties()->SetStringProperty(props, vr::Prop_SerialNumber_String, GetSerialNumber().c_str()); vr::VRProperties()->SetBoolProperty(props, vr::Prop_WillDriftInYaw_Bool, false); vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceIsWireless_Bool, true); @@ -75,25 +61,22 @@ vr::EVRInitError KnuckleDeviceDriver::Activate(uint32_t unObjectId) { vr::VRProperties()->SetStringProperty(props, vr::Prop_Firmware_ManualUpdateURL_String, "https://developer.valvesoftware.com/wiki/SteamVR/HowTo_Update_Firmware"); vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceProvidesBatteryStatus_Bool, true); vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceCanPowerOff_Bool, false); - vr::VRProperties()->SetInt32Property(props, vr::Prop_DeviceClass_Int32, (int32_t)vr::TrackedDeviceClass_Controller); + vr::VRProperties()->SetInt32Property(props, vr::Prop_DeviceClass_Int32, vr::TrackedDeviceClass_Controller); vr::VRProperties()->SetBoolProperty(props, vr::Prop_Firmware_ForceUpdateRequired_Bool, false); vr::VRProperties()->SetBoolProperty(props, vr::Prop_Identifiable_Bool, true); vr::VRProperties()->SetBoolProperty(props, vr::Prop_Firmware_RemindUpdate_Bool, false); vr::VRProperties()->SetInt32Property(props, vr::Prop_Axis0Type_Int32, vr::k_eControllerAxis_TrackPad); vr::VRProperties()->SetInt32Property(props, vr::Prop_Axis1Type_Int32, vr::k_eControllerAxis_Trigger); - vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerRoleHint_Int32, - IsRightHand() ? vr::TrackedControllerRole_RightHand : vr::TrackedControllerRole_LeftHand); + vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerRoleHint_Int32, IsRightHand() ? vr::TrackedControllerRole_RightHand : vr::TrackedControllerRole_LeftHand); vr::VRProperties()->SetBoolProperty(props, vr::Prop_HasDisplayComponent_Bool, false); vr::VRProperties()->SetBoolProperty(props, vr::Prop_HasCameraComponent_Bool, false); vr::VRProperties()->SetBoolProperty(props, vr::Prop_HasDriverDirectModeComponent_Bool, false); vr::VRProperties()->SetBoolProperty(props, vr::Prop_HasVirtualDisplayComponent_Bool, false); - vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerHandSelectionPriority_Int32, (int32_t)2147483647); + vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerHandSelectionPriority_Int32, 2147483647); vr::VRProperties()->SetStringProperty(props, vr::Prop_ModelNumber_String, IsRightHand() ? "Knuckles Right" : "Knuckles Left"); - vr::VRProperties()->SetStringProperty(props, vr::Prop_RenderModelName_String, - IsRightHand() ? "{indexcontroller}valve_controller_knu_1_0_right" : "{indexcontroller}valve_controller_knu_1_0_left"); - vr::VRProperties()->SetStringProperty(props, vr::Prop_ManufacturerName_String, c_deviceManufacturer); - vr::VRProperties()->SetStringProperty(props, vr::Prop_TrackingFirmwareVersion_String, - "1562916277 watchman@ValveBuilder02 2019-07-12 FPGA 538(2.26/10/2) BL 0 VRC 1562916277 Radio 1562882729"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_RenderModelName_String, IsRightHand() ? "{indexcontroller}valve_controller_knu_1_0_right" : "{indexcontroller}valve_controller_knu_1_0_left"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_ManufacturerName_String, c_deviceDriverManufacturer); + vr::VRProperties()->SetStringProperty(props, vr::Prop_TrackingFirmwareVersion_String, "1562916277 watchman@ValveBuilder02 2019-07-12 FPGA 538(2.26/10/2) BL 0 VRC 1562916277 Radio 1562882729"); vr::VRProperties()->SetStringProperty(props, vr::Prop_HardwareRevision_String, "product 17 rev 14.1.9 lot 2019/4/20 0"); vr::VRProperties()->SetStringProperty(props, vr::Prop_ConnectedWirelessDongle_String, "C2F75F5986-DIY"); vr::VRProperties()->SetUint64Property(props, vr::Prop_HardwareRevision_Uint64, 286130441U); @@ -104,174 +87,62 @@ vr::EVRInitError KnuckleDeviceDriver::Activate(uint32_t unObjectId) { vr::VRProperties()->SetUint64Property(props, vr::Prop_DongleVersion_Uint64, 1558748372U); vr::VRProperties()->SetStringProperty(props, vr::Prop_Firmware_ProgrammingTarget_String, IsRightHand() ? "LHR-E217CD01" : "LHR-E217CD00"); vr::VRProperties()->SetStringProperty(props, vr::Prop_ResourceRoot_String, "indexcontroller"); - vr::VRProperties()->SetStringProperty(props, vr::Prop_RegisteredDeviceType_String, - IsRightHand() ? "valve/index_controllerLHR-E217CD01" : "valve/index_controllerLHR-E217CD00"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_RegisteredDeviceType_String, IsRightHand() ? "valve/index_controllerLHR-E217CD01" : "valve/index_controllerLHR-E217CD00"); vr::VRProperties()->SetStringProperty(props, vr::Prop_InputProfilePath_String, "{indexcontroller}/input/index_controller_profile.json"); - vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceOff_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_off.png" : "{openglove}/icons/left_controller_status_off.png"); - vr::VRProperties()->SetStringProperty( - props, vr::Prop_NamedIconPathDeviceSearching_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_searching.gif" : "{openglove}/icons/left_controller_status_searching.gif"); - vr::VRProperties()->SetStringProperty( - props, vr::Prop_NamedIconPathDeviceSearchingAlert_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_searching_alert.gif" : "{openglove}/icons/left_controller_status_searching_alert.gif"); - vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceReady_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_ready.png" : "{openglove}/icons/left_controller_status_ready.png"); - vr::VRProperties()->SetStringProperty( - props, vr::Prop_NamedIconPathDeviceReadyAlert_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_ready_alert.png" : "{openglove}/icons/left_controller_status_ready_alert.png"); - vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceNotReady_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_error.png" : "{openglove}/icons/left_controller_status_error.png"); - vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceStandby_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_off.png" : "{openglove}/icons/left_controller_status_off.png"); - vr::VRProperties()->SetStringProperty( - props, vr::Prop_NamedIconPathDeviceAlertLow_String, - IsRightHand() ? "{openglove}/icons/right_controller_status_ready_low.png" : "{openglove}/icons/left_controller_status_ready_low.png"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceOff_String, IsRightHand() ? "{openglove}/icons/right_controller_status_off.png" : "{openglove}/icons/left_controller_status_off.png"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceSearching_String, IsRightHand() ? "{openglove}/icons/right_controller_status_searching.gif" : "{openglove}/icons/left_controller_status_searching.gif"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceSearchingAlert_String, IsRightHand() ? "{openglove}/icons/right_controller_status_searching_alert.gif" : "{openglove}/icons/left_controller_status_searching_alert.gif"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceReady_String, IsRightHand() ? "{openglove}/icons/right_controller_status_ready.png" : "{openglove}/icons/left_controller_status_ready.png"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceReadyAlert_String, IsRightHand() ? "{openglove}/icons/right_controller_status_ready_alert.png" : "{openglove}/icons/left_controller_status_ready_alert.png"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceNotReady_String, IsRightHand() ? "{openglove}/icons/right_controller_status_error.png" : "{openglove}/icons/left_controller_status_error.png"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceStandby_String, IsRightHand() ? "{openglove}/icons/right_controller_status_off.png" : "{openglove}/icons/left_controller_status_off.png"); + vr::VRProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceAlertLow_String, IsRightHand() ? "{openglove}/icons/right_controller_status_ready_low.png" : "{openglove}/icons/left_controller_status_ready_low.png"); vr::VRProperties()->SetInt32Property(props, vr::Prop_Axis2Type_Int32, vr::k_eControllerAxis_Trigger); vr::VRProperties()->SetStringProperty(props, vr::Prop_ControllerType_String, "knuckles"); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/system/click", &m_inputComponentHandles[ComponentIndex::SYSTEM_CLICK]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/system/touch", &m_inputComponentHandles[ComponentIndex::SYSTEM_TOUCH]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/trigger/click", &m_inputComponentHandles[ComponentIndex::TRIGGER_CLICK]); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/trigger/value", &m_inputComponentHandles[ComponentIndex::TRIGGER_VALUE], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/trackpad/x", &m_inputComponentHandles[ComponentIndex::TRACKPAD_X], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedTwoSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/trackpad/y", &m_inputComponentHandles[ComponentIndex::TRACKPAD_Y], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedTwoSided); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/trackpad/touch", &m_inputComponentHandles[ComponentIndex::TRACKPAD_TOUCH]); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/trackpad/force", &m_inputComponentHandles[ComponentIndex::TRACKPAD_FORCE], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/grip/touch", &m_inputComponentHandles[ComponentIndex::GRIP_TOUCH]); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/grip/force", &m_inputComponentHandles[ComponentIndex::GRIP_FORCE], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/grip/value", &m_inputComponentHandles[ComponentIndex::GRIP_VALUE], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/thumbstick/click", &m_inputComponentHandles[ComponentIndex::THUMBSTICK_CLICK]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/thumbstick/touch", &m_inputComponentHandles[ComponentIndex::THUMBSTICK_TOUCH]); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/thumbstick/x", &m_inputComponentHandles[ComponentIndex::THUMBSTICK_X], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedTwoSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/thumbstick/y", &m_inputComponentHandles[ComponentIndex::THUMBSTICK_Y], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedTwoSided); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/a/click", &m_inputComponentHandles[ComponentIndex::A_CLICK]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/a/touch", &m_inputComponentHandles[ComponentIndex::A_TOUCH]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/b/click", &m_inputComponentHandles[ComponentIndex::B_CLICK]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/b/touch", &m_inputComponentHandles[ComponentIndex::B_TOUCH]); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/index", &m_inputComponentHandles[ComponentIndex::FINGER_INDEX], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/middle", &m_inputComponentHandles[ComponentIndex::FINGER_MIDDLE], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/ring", &m_inputComponentHandles[ComponentIndex::FINGER_RING], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/pinky", &m_inputComponentHandles[ComponentIndex::FINGER_PINKY], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateHapticComponent(props, "/output/haptic", &m_haptic); - - vr::EVRInputError error = vr::VRDriverInput()->CreateSkeletonComponent(props, isRightHand ? "/input/skeleton/right" : "/input/skeleton/left", - isRightHand ? "/skeleton/hand/right" : "/skeleton/hand/left", "/pose/raw", - vr::VRSkeletalTracking_Partial, m_handTransforms, NUM_BONES, &m_skeletalComponentHandle); - - if (error != vr::VRInputError_None) { - DebugDriverLog("CreateSkeletonComponent failed. Error: %s\n", error); - } - - StartDevice(); - - m_hasActivated = true; - - return vr::VRInitError_None; + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/system/click", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::SystemClick)]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/system/touch", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::SystemTouch)]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/trigger/click", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TriggerClick)]); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/trigger/value", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TriggerValue)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/trackpad/x", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TrackpadX)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/trackpad/y", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TrackpadY)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/trackpad/touch", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TrackpadTouch)]); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/trackpad/force", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TrackpadForce)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/grip/touch", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::GripTouch)]); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/grip/force", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::GripForce)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/grip/value", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::GripValue)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/thumbstick/click", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickClick)]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/thumbstick/touch", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickTouch)]); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/thumbstick/x", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickX)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/thumbstick/y", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickY)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/a/click", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::AClick)]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/a/touch", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ATouch)]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/b/click", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::BClick)]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/b/touch", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::BTouch)]); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/index", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerIndex)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/middle", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerMiddle)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/ring", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerRing)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/pinky", &inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerPinky)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateHapticComponent(props, "/output/haptic", &haptic_); + // clang-format on } -// This could do with a rename, its a bit vague as to what it does -void KnuckleDeviceDriver::StartDevice() { - m_ffbProvider = std::make_unique( - [&](VRFFBData_t data) { +void KnuckleDeviceDriver::StartingDevice() { + if (!configuration_.feedbackEnabled) return; + + ffbProvider_ = std::make_unique( + [&](const VRFFBData data) { // Queue the force feedback data for sending. - m_communicationManager->QueueSend(data); + communicationManager_->QueueSend(data); }, - m_configuration.role); - m_ffbProvider->Start(); - - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithoutController, IsRightHand() ? rightOpenPose : leftOpenPose, - NUM_BONES); - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithController, IsRightHand() ? rightOpenPose : leftOpenPose, - NUM_BONES); - - m_communicationManager->BeginListener([&](VRCommData_t datas) { - try { - m_boneAnimator->ComputeSkeletonTransforms(m_handTransforms, datas.flexion, IsRightHand()); - - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithoutController, m_handTransforms, NUM_BONES); - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithController, m_handTransforms, NUM_BONES); + configuration_.role); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::THUMBSTICK_X], datas.joyX, 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::THUMBSTICK_Y], datas.joyY, 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::THUMBSTICK_CLICK], datas.joyButton, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::THUMBSTICK_TOUCH], datas.joyButton, 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::TRIGGER_CLICK], datas.trgButton, 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::TRIGGER_VALUE], datas.flexion[1], 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::A_CLICK], datas.aButton, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::A_TOUCH], datas.aButton, 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::B_CLICK], datas.bButton, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::B_TOUCH], datas.bButton, 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::GRIP_FORCE], datas.grab, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::GRIP_TOUCH], datas.grab, 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::GRIP_VALUE], datas.grab, 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::SYSTEM_CLICK], datas.menu, 0); - - // We don't have a thumb on the index - // vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::THUMB], datas.flexion[0], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::FINGER_INDEX], datas.flexion[1], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::FINGER_MIDDLE], datas.flexion[2], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::FINGER_RING], datas.flexion[3], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::FINGER_PINKY], datas.flexion[4], 0); - - if (datas.calibrate) { - if (!m_controllerPose->isCalibrating()) m_controllerPose->StartCalibration(); - } else { - if (m_controllerPose->isCalibrating()) m_controllerPose->CompleteCalibration(); - } - - } catch (const std::exception&) { - DebugDriverLog("Exception caught while parsing comm data"); - } - }); + ffbProvider_->Start(); } -vr::DriverPose_t KnuckleDeviceDriver::GetPose() { - if (m_hasActivated) return m_controllerPose->UpdatePose(); - - vr::DriverPose_t pose = {0}; - return pose; -} - -void KnuckleDeviceDriver::RunFrame() { - if (m_hasActivated) { - vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_driverId, m_controllerPose->UpdatePose(), sizeof(vr::DriverPose_t)); - } -} - -void KnuckleDeviceDriver::Deactivate() { - if (m_hasActivated) { - m_communicationManager->Disconnect(); - m_ffbProvider->Stop(); - m_driverId = vr::k_unTrackedDeviceIndexInvalid; +void KnuckleDeviceDriver::StoppingDevice() { + if (ffbProvider_) { + ffbProvider_->Stop(); } } - -void* KnuckleDeviceDriver::GetComponent(const char* pchComponentNameAndVersion) { return nullptr; } - -void KnuckleDeviceDriver::EnterStandby() {} - -void KnuckleDeviceDriver::DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) { - if (unResponseBufferSize >= 1) { - pchResponseBuffer[0] = 0; - } -} \ No newline at end of file diff --git a/src/DeviceDriver/LucidGloveDriver.cpp b/src/DeviceDriver/LucidGloveDriver.cpp index d0b015f8..fb77d97e 100644 --- a/src/DeviceDriver/LucidGloveDriver.cpp +++ b/src/DeviceDriver/LucidGloveDriver.cpp @@ -1,184 +1,78 @@ #include "DeviceDriver/LucidGloveDriver.h" -#include "DriverLog.h" - -static const char* c_deviceManufacturer = "LucidVR"; static const char* c_deviceControllerType = "lucidgloves"; static const char* c_deviceModelNumber = "lucidgloves1"; static const char* c_basePosePath = "/pose/raw"; static const char* c_inputProfilePath = "{openglove}/input/openglove_profile.json"; -enum ComponentIndex : int { - COMP_JOY_X = 0, - COMP_JOY_Y = 1, - COMP_JOY_BTN = 2, - COMP_BTN_TRG = 3, - COMP_BTN_A = 4, - COMP_BTN_B = 5, - COMP_GES_GRAB = 6, - COMP_GES_PINCH = 7, - COMP_HAPTIC = 8, - COMP_TRG_THUMB = 9, - COMP_TRG_INDEX = 10, - COMP_TRG_MIDDLE = 11, - COMP_TRG_RING = 12, - COMP_TRG_PINKY = 13, - COMP_BTN_MENU = 14, -}; - -LucidGloveDeviceDriver::LucidGloveDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, - std::string serialNumber, std::shared_ptr boneAnimator) - : m_configuration(configuration), - m_communicationManager(std::move(communicationManager)), - m_boneAnimator(std::move(boneAnimator)), - m_serialNumber(serialNumber), - m_driverId(-1), - m_hasActivated(false) { - // copy a default bone transform to our hand transform for use in finger positioning later - std::copy(std::begin(m_configuration.role == vr::TrackedControllerRole_RightHand ? rightOpenPose : leftOpenPose), - std::end(m_configuration.role == vr::TrackedControllerRole_RightHand ? rightOpenPose : leftOpenPose), std::begin(m_handTransforms)); +LucidGloveDeviceDriver::LucidGloveDeviceDriver( + std::unique_ptr communicationManager, + std::shared_ptr boneAnimator, + const std::string& serialNumber, + const VRDeviceConfiguration configuration) + : DeviceDriver(std::move(communicationManager), std::move(boneAnimator), serialNumber, configuration), inputComponentHandles_() {} + +void LucidGloveDeviceDriver::HandleInput(const VRInputData data) { + // clang-format off + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::JoyX)], data.joyX, 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::JoyY)], data.joyY, 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::JoyBtn)], data.joyButton, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnTrg)], data.trgButton, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnA)], data.aButton, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnB)], data.bButton, 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::GesGrab)], data.grab, 0); + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::GesPinch)], data.pinch, 0); + + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgThumb)], data.flexion[0], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgIndex)], data.flexion[1], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgMiddle)], data.flexion[2], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgRing)], data.flexion[3], 0); + vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgPinky)], data.flexion[4], 0); + + vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnMenu)], data.menu, 0); + // clang-format on } -bool LucidGloveDeviceDriver::IsRightHand() const { return m_configuration.role == vr::TrackedControllerRole_RightHand; } - -std::string LucidGloveDeviceDriver::GetSerialNumber() { return m_serialNumber; } - -bool LucidGloveDeviceDriver::IsActive() { return m_hasActivated; } - -vr::EVRInitError LucidGloveDeviceDriver::Activate(uint32_t unObjectId) { +void LucidGloveDeviceDriver::SetupProps(vr::PropertyContainerHandle_t& props) { const bool isRightHand = IsRightHand(); - m_driverId = unObjectId; // unique ID for your driver - m_controllerPose = std::make_unique(m_configuration.role, std::string(c_deviceManufacturer), m_configuration.poseConfiguration); - - vr::PropertyContainerHandle_t props = - vr::VRProperties()->TrackedDeviceToPropertyContainer(m_driverId); // this gets a container object where you store all the information about your driver - - vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerHandSelectionPriority_Int32, (int32_t)2147483647); + // clang-format off + vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerHandSelectionPriority_Int32, 2147483647); vr::VRProperties()->SetStringProperty(props, vr::Prop_InputProfilePath_String, c_inputProfilePath); // tell OpenVR where to get your driver's Input Profile - vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerRoleHint_Int32, m_configuration.role); // tells OpenVR what kind of device this is + vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerRoleHint_Int32, configuration_.role); // tells OpenVR what kind of device this is vr::VRProperties()->SetStringProperty(props, vr::Prop_SerialNumber_String, GetSerialNumber().c_str()); vr::VRProperties()->SetStringProperty(props, vr::Prop_ModelNumber_String, c_deviceModelNumber); - vr::VRProperties()->SetStringProperty(props, vr::Prop_ManufacturerName_String, c_deviceManufacturer); - vr::VRProperties()->SetInt32Property(props, vr::Prop_DeviceClass_Int32, (int32_t)vr::TrackedDeviceClass_Controller); + vr::VRProperties()->SetStringProperty(props, vr::Prop_ManufacturerName_String, c_deviceDriverManufacturer); + vr::VRProperties()->SetInt32Property(props, vr::Prop_DeviceClass_Int32, vr::TrackedDeviceClass_Controller); vr::VRProperties()->SetStringProperty(props, vr::Prop_ControllerType_String, c_deviceControllerType); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/joystick/x", &m_inputComponentHandles[ComponentIndex::COMP_JOY_X], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedTwoSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/joystick/y", &m_inputComponentHandles[ComponentIndex::COMP_JOY_Y], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedTwoSided); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/joystick/click", &m_inputComponentHandles[ComponentIndex::COMP_JOY_BTN]); - - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/trigger/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_TRG]); - - vr::VRDriverInput()->CreateBooleanComponent(props, isRightHand ? "/input/A/click" : "/input/system/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_A]); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/joystick/x", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::JoyX)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/joystick/y", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::JoyY)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/joystick/click", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::JoyBtn)]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/B/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_B]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/trigger/click", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnTrg)]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/grab/click", &m_inputComponentHandles[ComponentIndex::COMP_GES_GRAB]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/pinch/click", &m_inputComponentHandles[ComponentIndex::COMP_GES_PINCH]); + vr::VRDriverInput()->CreateBooleanComponent(props, isRightHand ? "/input/A/click" : "/input/system/click", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnA)]); - vr::VRDriverInput()->CreateHapticComponent(props, "output/haptic", &m_inputComponentHandles[ComponentIndex::COMP_HAPTIC]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/B/click", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnB)]); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/thumb", &m_inputComponentHandles[ComponentIndex::COMP_TRG_THUMB], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/index", &m_inputComponentHandles[ComponentIndex::COMP_TRG_INDEX], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/middle", &m_inputComponentHandles[ComponentIndex::COMP_TRG_MIDDLE], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/ring", &m_inputComponentHandles[ComponentIndex::COMP_TRG_RING], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); - vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/pinky", &m_inputComponentHandles[ComponentIndex::COMP_TRG_PINKY], vr::VRScalarType_Absolute, - vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/grab/click", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::GesGrab)]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/pinch/click", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::GesPinch)]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/system/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_MENU]); + vr::VRDriverInput()->CreateHapticComponent(props, "output/haptic", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::Haptic)]); - // Create the skeletal component and save the handle for later use// + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/thumb", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgThumb)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/index", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgIndex)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/middle", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgMiddle)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/ring", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgRing)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + vr::VRDriverInput()->CreateScalarComponent(props, "/input/finger/pinky", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgPinky)], vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); - vr::EVRInputError error = vr::VRDriverInput()->CreateSkeletonComponent( - props, isRightHand ? "/input/skeleton/right" : "/input/skeleton/left", isRightHand ? "/skeleton/hand/right" : "/skeleton/hand/left", "/pose/raw", - vr::VRSkeletalTracking_Partial, isRightHand ? rightOpenPose : leftOpenPose, NUM_BONES, &m_skeletalComponentHandle); - - if (error != vr::VRInputError_None) { - // Handle failure case - DebugDriverLog("CreateSkeletonComponent failed. Error: %s\n", error); - } - - StartDevice(); - - m_hasActivated = true; - - return vr::VRInitError_None; + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/system/click", &inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnMenu)]); + // clang-format on } -void LucidGloveDeviceDriver::StartDevice() { - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithoutController, m_handTransforms, NUM_BONES); - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithController, m_handTransforms, NUM_BONES); - - m_communicationManager->BeginListener([&](VRCommData_t datas) { - try { - m_boneAnimator->ComputeSkeletonTransforms(m_handTransforms, datas.flexion, IsRightHand()); - - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithoutController, m_handTransforms, NUM_BONES); - vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletalComponentHandle, vr::VRSkeletalMotionRange_WithController, m_handTransforms, NUM_BONES); - - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::COMP_JOY_X], datas.joyX, 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::COMP_JOY_Y], datas.joyY, 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::COMP_JOY_BTN], datas.joyButton, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::COMP_BTN_TRG], datas.trgButton, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::COMP_BTN_A], datas.aButton, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::COMP_BTN_B], datas.bButton, 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::COMP_GES_GRAB], datas.grab, 0); - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::COMP_GES_PINCH], datas.pinch, 0); - - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::COMP_TRG_THUMB], datas.flexion[0], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::COMP_TRG_INDEX], datas.flexion[1], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::COMP_TRG_MIDDLE], datas.flexion[2], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::COMP_TRG_RING], datas.flexion[3], 0); - vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::COMP_TRG_PINKY], datas.flexion[4], 0); - - vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::COMP_BTN_MENU], datas.menu, 0); - - if (datas.calibrate) { - if (!m_controllerPose->isCalibrating()) m_controllerPose->StartCalibration(); - } else { - if (m_controllerPose->isCalibrating()) m_controllerPose->CompleteCalibration(); - } - - } catch (const std::exception&) { - DriverLog("Exception caught while parsing comm data"); - } - }); -} - -vr::DriverPose_t LucidGloveDeviceDriver::GetPose() { - if (m_hasActivated) return m_controllerPose->UpdatePose(); - - vr::DriverPose_t pose = {0}; - return pose; -} - -void LucidGloveDeviceDriver::RunFrame() { - if (m_hasActivated) { - vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_driverId, m_controllerPose->UpdatePose(), sizeof(vr::DriverPose_t)); - } -} - -void LucidGloveDeviceDriver::Deactivate() { - if (m_hasActivated) { - m_communicationManager->Disconnect(); - m_driverId = vr::k_unTrackedDeviceIndexInvalid; - } -} - -void* LucidGloveDeviceDriver::GetComponent(const char* pchComponentNameAndVersion) { return nullptr; } - -void LucidGloveDeviceDriver::EnterStandby() {} +void LucidGloveDeviceDriver::StartingDevice() {} -void LucidGloveDeviceDriver::DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) { - if (unResponseBufferSize >= 1) { - pchResponseBuffer[0] = 0; - } -} \ No newline at end of file +void LucidGloveDeviceDriver::StoppingDevice() {} diff --git a/src/DeviceFactory.cpp b/src/DeviceFactory.cpp index 7c53724f..db9c1afb 100644 --- a/src/DeviceFactory.cpp +++ b/src/DeviceFactory.cpp @@ -1,29 +1,28 @@ #include -#include "DriverLog.h" #include "DeviceProvider.h" +#include "DriverLog.h" #if defined(_WIN32) -#define HMD_DLL_EXPORT extern "C" __declspec( dllexport ) -#define HMD_DLL_IMPORT extern "C" __declspec( dllimport ) +#define HMD_DLL_EXPORT extern "C" __declspec(dllexport) +#define HMD_DLL_IMPORT extern "C" __declspec(dllimport) #elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(__APPLE__) #define HMD_DLL_EXPORT extern "C" __attribute__((visibility("default"))) -#define HMD_DLL_IMPORT extern "C" +#define HMD_DLL_IMPORT extern "C" #else #error "Unsupported Platform." #endif -DeviceProvider deviceProvider; //global, single instance, of the class that provides OpenVR with all of your devices. +DeviceProvider deviceProvider; // global, single instance, of the class that provides OpenVR with all of your devices. /** This method returns an instance of your provider that OpenVR uses. **/ HMD_DLL_EXPORT void* HmdDriverFactory(const char* interfaceName, int* returnCode) { - - if (0 == strcmp(vr::IServerTrackedDeviceProvider_Version, interfaceName)) { - return &deviceProvider; - } - DriverLog("HmdDriverFactory called for %s", interfaceName); - return nullptr; + if (0 == strcmp(vr::IServerTrackedDeviceProvider_Version, interfaceName)) { + return &deviceProvider; + } + DriverLog("HmdDriverFactory called for %s", interfaceName); + return nullptr; } \ No newline at end of file diff --git a/src/DeviceProvider.cpp b/src/DeviceProvider.cpp index 5be67284..4084d62f 100644 --- a/src/DeviceProvider.cpp +++ b/src/DeviceProvider.cpp @@ -1,89 +1,73 @@ #include -#include +#include -#include #include +#include #include "Communication/BTSerialCommunicationManager.h" +#include "Communication/NamedPipeCommunicationManager.h" #include "Communication/SerialCommunicationManager.h" #include "DeviceDriver/KnuckleDriver.h" #include "DeviceDriver/LucidGloveDriver.h" #include "DriverLog.h" #include "Encode/AlphaEncodingManager.h" #include "Encode/LegacyEncodingManager.h" -#include "Quaternion.h" +#include "Util/Quaternion.h" #include "Util/Windows.h" -static bool CreateBackgroundProcess() { - STARTUPINFOA si; - PROCESS_INFORMATION pi; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - const std::string driverPath = GetDriverPath(); - DriverLog("Path to DLL: %s", driverPath.c_str()); - - std::string path = driverPath + "\\openglove_overlay.exe"; - - bool success = true; - if (!CreateProcess(path.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) success = false; - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return success; -} - vr::EVRInitError DeviceProvider::Init(vr::IVRDriverContext* pDriverContext) { - vr::EVRInitError initError = InitServerDriverContext(pDriverContext); - if (initError != vr::EVRInitError::VRInitError_None) return initError; + if (const vr::EVRInitError initError = InitServerDriverContext(pDriverContext); initError != vr::EVRInitError::VRInitError_None) return initError; - VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext); + VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext) InitDriverLog(vr::VRDriverLog()); + + //this won't print if running in release DebugDriverLog("OpenGlove is running in DEBUG mode"); - if (!CreateBackgroundProcess()) { - DriverLog("Could not create background process"); + const std::string driverPath = GetDriverPath(); + DriverLog("Path to DLL: %s", driverPath.c_str()); + + // Create background process for the overlay (used for finding controllers to bind to for tracking) + if (!CreateBackgroundProcess(driverPath + R"(\bin\win64\openglove_overlay.exe)")) { + DriverLog("Could not create background process: %c", GetLastErrorAsString().c_str()); + return vr::VRInitError_Init_FileNotFound; } - VRDeviceConfiguration_t leftConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_LeftHand); - VRDeviceConfiguration_t rightConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_RightHand); - - std::string driverPath = GetDriverPath(); - - const std::string unwanted = "\\bin\\win64"; - driverPath.erase(driverPath.find(unwanted), unwanted.length()); + const VRDeviceConfiguration leftConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_LeftHand); + const VRDeviceConfiguration rightConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_RightHand); - std::shared_ptr boneAnimator = std::make_shared(driverPath + "\\resources\\anims\\glove_anim.glb"); + const auto boneAnimator = std::make_shared(driverPath + R"(\resources\anims\glove_anim.glb)"); if (leftConfiguration.enabled) { - m_leftHand = InstantiateDeviceDriver(leftConfiguration, boneAnimator); - vr::VRServerDriverHost()->TrackedDeviceAdded(m_leftHand->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_leftHand.get()); + leftHand_ = InstantiateDeviceDriver(leftConfiguration, boneAnimator); + vr::VRServerDriverHost()->TrackedDeviceAdded(leftHand_->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, leftHand_.get()); } + if (rightConfiguration.enabled) { - m_rightHand = InstantiateDeviceDriver(rightConfiguration, boneAnimator); - vr::VRServerDriverHost()->TrackedDeviceAdded(m_rightHand->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_rightHand.get()); + rightHand_ = InstantiateDeviceDriver(rightConfiguration, boneAnimator); + vr::VRServerDriverHost()->TrackedDeviceAdded(rightHand_->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, rightHand_.get()); } return vr::VRInitError_None; } -std::unique_ptr DeviceProvider::InstantiateDeviceDriver(VRDeviceConfiguration_t configuration, std::shared_ptr boneAnimator) { - std::unique_ptr communicationManager; - std::unique_ptr encodingManager; +std::unique_ptr DeviceProvider::InstantiateDeviceDriver( + VRDeviceConfiguration configuration, std::shared_ptr boneAnimator) const { + std::unique_ptr communicationManager; + std::unique_ptr encodingManager; + + const bool isRightHand = configuration.role == vr::TrackedControllerRole_RightHand; - bool isRightHand = configuration.role == vr::TrackedControllerRole_RightHand; switch (configuration.encodingProtocol) { default: DriverLog("No encoding protocol set. Using legacy."); - case VREncodingProtocol::LEGACY: { + case VREncodingProtocol::Legacy: { const float maxAnalogValue = vr::VRSettings()->GetFloat(c_legacyEncodingSettingsSection, "max_analog_value"); encodingManager = std::make_unique(maxAnalogValue); break; } - case VREncodingProtocol::ALPHA: { + case VREncodingProtocol::Alpha: { const float maxAnalogValue = vr::VRSettings()->GetFloat(c_alphaEncodingSettingsSection, "max_analog_value"); encodingManager = std::make_unique(maxAnalogValue); break; @@ -91,87 +75,123 @@ std::unique_ptr DeviceProvider::InstantiateDeviceDriver(VRDeviceC } switch (configuration.communicationProtocol) { - case VRCommunicationProtocol::BTSERIAL: { + case VRCommunicationProtocol::NamedPipe: { + DriverLog("Communication set to Named Pipe"); + const std::string path = R"(\\.\pipe\vrapplication\input\)" + std::string(isRightHand ? "right" : "left"); + VRNamedPipeInputConfiguration namedPipeConfiguration(path); + communicationManager = std::make_unique(namedPipeConfiguration, configuration); + break; + } + case VRCommunicationProtocol::BtSerial: { DriverLog("Communication set to BTSerial"); char name[248]; - vr::VRSettings()->GetString(c_btserialCommunicationSettingsSection, isRightHand ? "right_name" : "left_name", name, sizeof(name)); - VRBTSerialConfiguration_t btSerialSettings(name); - communicationManager = std::make_unique(btSerialSettings, std::move(encodingManager)); + vr::VRSettings()->GetString(c_btserialCommunicationSettingsSection, isRightHand ? "right_name" : "left_name", name, sizeof name); + VRBTSerialConfiguration btSerialSettings(name); + communicationManager = + std::make_unique(std::move(encodingManager), btSerialSettings, configuration); break; } default: DriverLog("No communication protocol set. Using serial."); - case VRCommunicationProtocol::SERIAL: + case VRCommunicationProtocol::Serial: char port[16]; - vr::VRSettings()->GetString(c_serialCommunicationSettingsSection, isRightHand ? "right_port" : "left_port", port, sizeof(port)); + vr::VRSettings()->GetString(c_serialCommunicationSettingsSection, isRightHand ? "right_port" : "left_port", port, sizeof port); const int baudRate = vr::VRSettings()->GetInt32(c_serialCommunicationSettingsSection, "baud_rate"); - VRSerialConfiguration_t serialSettings(port, baudRate); + VRSerialConfiguration serialSettings(port, baudRate); - communicationManager = std::make_unique(serialSettings, std::move(encodingManager)); + communicationManager = + std::make_unique(std::move(encodingManager), serialSettings, configuration); break; } switch (configuration.deviceDriver) { - case VRDeviceDriver::EMULATED_KNUCKLES: { + case VRDeviceDriver::EmulatedKnuckles: { char serialNumber[32]; - vr::VRSettings()->GetString(c_knuckleDeviceSettingsSection, isRightHand ? "right_serial_number" : "left_serial_number", serialNumber, sizeof(serialNumber)); - - return std::make_unique(configuration, std::move(communicationManager), serialNumber, std::move(boneAnimator)); + vr::VRSettings()->GetString( + c_knuckleDeviceSettingsSection, isRightHand ? "right_serial_number" : "left_serial_number", serialNumber, sizeof serialNumber); + bool approximateThumb = vr::VRSettings()->GetBool( + c_knuckleDeviceSettingsSection, "approximate_thumb"); + return std::make_unique( + std::move(communicationManager), std::move(boneAnimator), serialNumber, approximateThumb, configuration); } default: DriverLog("No device driver selected. Using lucidgloves."); - case VRDeviceDriver::LUCIDGLOVES: { + case VRDeviceDriver::LucidGloves: { char serialNumber[32]; - vr::VRSettings()->GetString(c_lucidGloveDeviceSettingsSection, isRightHand ? "right_serial_number" : "left_serial_number", serialNumber, sizeof(serialNumber)); + vr::VRSettings()->GetString( + c_lucidGloveDeviceSettingsSection, isRightHand ? "right_serial_number" : "left_serial_number", serialNumber, sizeof serialNumber); - return std::make_unique(configuration, std::move(communicationManager), serialNumber, std::move(boneAnimator)); + return std::make_unique( + std::move(communicationManager), std::move(boneAnimator), serialNumber, configuration); } } } -VRDeviceConfiguration_t DeviceProvider::GetDeviceConfiguration(vr::ETrackedControllerRole role) { + +VRDeviceConfiguration DeviceProvider::GetDeviceConfiguration(const vr::ETrackedControllerRole role) { const bool isRightHand = role == vr::TrackedControllerRole_RightHand; const bool isEnabled = vr::VRSettings()->GetBool(c_driverSettingsSection, isRightHand ? "right_enabled" : "left_enabled"); + const bool feedbackEnabled = vr::VRSettings()->GetBool(c_driverSettingsSection, "feedback_enabled"); - const auto communicationProtocol = (VRCommunicationProtocol)vr::VRSettings()->GetInt32(c_driverSettingsSection, "communication_protocol"); - const auto encodingProtocol = (VREncodingProtocol)vr::VRSettings()->GetInt32(c_driverSettingsSection, "encoding_protocol"); - const auto deviceDriver = (VRDeviceDriver)vr::VRSettings()->GetInt32(c_driverSettingsSection, "device_driver"); + const auto communicationProtocol = + static_cast(vr::VRSettings()->GetInt32(c_driverSettingsSection, "communication_protocol")); + const auto encodingProtocol = static_cast(vr::VRSettings()->GetInt32(c_driverSettingsSection, "encoding_protocol")); + const auto deviceDriver = static_cast(vr::VRSettings()->GetInt32(c_driverSettingsSection, "device_driver")); const float poseTimeOffset = vr::VRSettings()->GetFloat(c_poseSettingsSection, "pose_time_offset"); - const float offsetXPos = vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_position" : "left_x_offset_position"); - const float offsetYPos = vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_position" : "left_y_offset_position"); - const float offsetZPos = vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_position" : "left_z_offset_position"); + const float offsetXPos = + vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_position" : "left_x_offset_position"); + const float offsetYPos = + vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_position" : "left_y_offset_position"); + const float offsetZPos = + vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_position" : "left_z_offset_position"); - const float offsetXRot = vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_degrees" : "left_x_offset_degrees"); - const float offsetYRot = vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_degrees" : "left_y_offset_degrees"); - const float offsetZRot = vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_degrees" : "left_z_offset_degrees"); + const float offsetXRot = + vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_x_offset_degrees" : "left_x_offset_degrees"); + const float offsetYRot = + vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_y_offset_degrees" : "left_y_offset_degrees"); + const float offsetZRot = + vr::VRSettings()->GetFloat(c_poseSettingsSection, isRightHand ? "right_z_offset_degrees" : "left_z_offset_degrees"); const bool controllerOverrideEnabled = vr::VRSettings()->GetBool(c_poseSettingsSection, "controller_override"); const int controllerIdOverride = - controllerOverrideEnabled ? vr::VRSettings()->GetInt32(c_poseSettingsSection, isRightHand ? "controller_override_right" : "controller_override_left") : -1; + controllerOverrideEnabled + ? vr::VRSettings()->GetInt32(c_poseSettingsSection, isRightHand ? "controller_override_right" : "controller_override_left") + : -1; + const bool calibrationButton = vr::VRSettings()->GetBool(c_poseSettingsSection, "hardware_calibration_button_enabled"); const vr::HmdVector3_t offsetVector = {offsetXPos, offsetYPos, offsetZPos}; // Convert the rotation to a quaternion - const vr::HmdQuaternion_t angleOffsetQuaternion = EulerToQuaternion(DegToRad(offsetXRot), DegToRad(offsetYRot), DegToRad(offsetZRot)); - - return VRDeviceConfiguration_t(role, isEnabled, - VRPoseConfiguration_t(offsetVector, angleOffsetQuaternion, poseTimeOffset, controllerOverrideEnabled, controllerIdOverride), - encodingProtocol, communicationProtocol, deviceDriver); + const vr::HmdQuaternion_t angleOffsetQuaternion = + EulerToQuaternion(DegToRad(offsetXRot), DegToRad(offsetYRot), DegToRad(offsetZRot)); + + return VRDeviceConfiguration( + role, + isEnabled, + feedbackEnabled, + VRPoseConfiguration(offsetVector, angleOffsetQuaternion, poseTimeOffset, controllerOverrideEnabled, controllerIdOverride, calibrationButton), + encodingProtocol, + communicationProtocol, + deviceDriver); } void DeviceProvider::Cleanup() {} -const char* const* DeviceProvider::GetInterfaceVersions() { return vr::k_InterfaceVersions; } +const char* const* DeviceProvider::GetInterfaceVersions() { + return vr::k_InterfaceVersions; +} void DeviceProvider::RunFrame() { - if (m_leftHand && m_leftHand->IsActive()) m_leftHand->RunFrame(); - if (m_rightHand && m_rightHand->IsActive()) m_rightHand->RunFrame(); + if (leftHand_ && leftHand_->IsActive()) leftHand_->RunFrame(); + if (rightHand_ && rightHand_->IsActive()) rightHand_->RunFrame(); } -bool DeviceProvider::ShouldBlockStandbyMode() { return false; } +bool DeviceProvider::ShouldBlockStandbyMode() { + return false; +} void DeviceProvider::EnterStandby() {} diff --git a/src/DriverLog.cpp b/src/DriverLog.cpp index 7eea2f8f..8b9cc6ca 100644 --- a/src/DriverLog.cpp +++ b/src/DriverLog.cpp @@ -2,48 +2,44 @@ #include "DriverLog.h" -#include -#include +#include +#include -static vr::IVRDriverLog* s_pLogFile = NULL; +static vr::IVRDriverLog* s_pLogFile = nullptr; bool InitDriverLog(vr::IVRDriverLog* pDriverLog) { - if (s_pLogFile) - return false; - s_pLogFile = pDriverLog; - return s_pLogFile != NULL; + if (s_pLogFile) return false; + s_pLogFile = pDriverLog; + return s_pLogFile != nullptr; } void CleanupDriverLog() { - s_pLogFile = NULL; + s_pLogFile = nullptr; } static void DriverLogVarArgs(const char* pMsgFormat, va_list args) { - char buf[1024]; - vsnprintf(buf, sizeof(buf), pMsgFormat, args); + char buf[1024]; + vsnprintf(buf, sizeof buf, pMsgFormat, args); - if (s_pLogFile) - s_pLogFile->Log(buf); + if (s_pLogFile) s_pLogFile->Log(buf); } +void DriverLog(const char* pchFormat, ...) { + va_list args; + va_start(args, pchFormat); -void DriverLog(const char* pMsgFormat, ...) { - va_list args; - va_start(args, pMsgFormat); + DriverLogVarArgs(pchFormat, args); - DriverLogVarArgs(pMsgFormat, args); - - va_end(args); + va_end(args); } - -void DebugDriverLog(const char* pMsgFormat, ...) { +void DebugDriverLog(const char* pchFormat, ...) { #ifdef _DEBUG - va_list args; - va_start(args, pMsgFormat); + va_list args; + va_start(args, pchFormat); - DriverLogVarArgs(pMsgFormat, args); + DriverLogVarArgs(pchFormat, args); - va_end(args); + va_end(args); #endif } \ No newline at end of file diff --git a/src/Encode/AlphaEncodingManager.cpp b/src/Encode/AlphaEncodingManager.cpp index defbf1a2..d6c5b945 100644 --- a/src/Encode/AlphaEncodingManager.cpp +++ b/src/Encode/AlphaEncodingManager.cpp @@ -1,95 +1,111 @@ #include #include -#include - -#include "DriverLog.h" /* Alpha encoding uses the wasted data in the delimiter from legacy to allow for optional arguments and redundancy over smaller packets */ enum class VRCommDataAlphaEncodingCharacter : char { - FIN_THUMB = 'A', - FIN_INDEX = 'B', - FIN_MIDDLE = 'C', - FIN_RING = 'D', - FIN_PINKY = 'E', - JOY_X = 'F', - JOY_Y = 'G', - JOY_BTN = 'H', - BTN_TRG = 'I', - BTN_A = 'J', - BTN_B = 'K', - GES_GRAB = 'L', - GES_PINCH = 'M', - BTN_MENU = 'N', - BTN_CALIB = 'O', + FinThumb = 'A', + FinIndex = 'B', + FinMiddle = 'C', + FinRing = 'D', + FinPinky = 'E', + JoyX = 'F', + JoyY = 'G', + JoyBtn = 'H', + BtnTrg = 'I', + BtnA = 'J', + BtnB = 'K', + GesGrab = 'L', + GesPinch = 'M', + BtnMenu = 'N', + BtnCalib = 'O', }; -const char VRCommDataAlphaEncodingCharacters[] = { - (char)VRCommDataAlphaEncodingCharacter::FIN_THUMB, - (char)VRCommDataAlphaEncodingCharacter::FIN_INDEX, - (char)VRCommDataAlphaEncodingCharacter::FIN_MIDDLE, - (char)VRCommDataAlphaEncodingCharacter::FIN_RING, - (char)VRCommDataAlphaEncodingCharacter::FIN_PINKY, - (char)VRCommDataAlphaEncodingCharacter::JOY_X, - (char)VRCommDataAlphaEncodingCharacter::JOY_Y, - (char)VRCommDataAlphaEncodingCharacter::JOY_BTN, - (char)VRCommDataAlphaEncodingCharacter::BTN_TRG, - (char)VRCommDataAlphaEncodingCharacter::BTN_A, - (char)VRCommDataAlphaEncodingCharacter::BTN_B, - (char)VRCommDataAlphaEncodingCharacter::GES_GRAB, - (char)VRCommDataAlphaEncodingCharacter::GES_PINCH, - (char)VRCommDataAlphaEncodingCharacter::BTN_MENU, - (char)VRCommDataAlphaEncodingCharacter::BTN_CALIB, - (char)0 // Turns into a null terminated string +constexpr char VRCommDataAlphaEncodingCharacters[] = { + static_cast(VRCommDataAlphaEncodingCharacter::FinThumb), + static_cast(VRCommDataAlphaEncodingCharacter::FinIndex), + static_cast(VRCommDataAlphaEncodingCharacter::FinMiddle), + static_cast(VRCommDataAlphaEncodingCharacter::FinRing), + static_cast(VRCommDataAlphaEncodingCharacter::FinPinky), + static_cast(VRCommDataAlphaEncodingCharacter::JoyX), + static_cast(VRCommDataAlphaEncodingCharacter::JoyY), + static_cast(VRCommDataAlphaEncodingCharacter::JoyBtn), + static_cast(VRCommDataAlphaEncodingCharacter::BtnTrg), + static_cast(VRCommDataAlphaEncodingCharacter::BtnA), + static_cast(VRCommDataAlphaEncodingCharacter::BtnB), + static_cast(VRCommDataAlphaEncodingCharacter::GesGrab), + static_cast(VRCommDataAlphaEncodingCharacter::GesPinch), + static_cast(VRCommDataAlphaEncodingCharacter::BtnMenu), + static_cast(VRCommDataAlphaEncodingCharacter::BtnCalib), + static_cast(0 // Turns into a null terminated string + ) // Turns into a null terminated string }; -static std::string getArgumentSubstring(std::string str, char del) { - size_t start = str.find(del); +static std::string getArgumentSubstring(const std::string& str, const char del) { + const size_t start = str.find(del); + if (start == std::string::npos) return std::string(); - size_t end = str.find_first_of(VRCommDataAlphaEncodingCharacters, start + 1); // characters may not necessarily be in order, so end at any letter + + const size_t end = + str.find_first_of(VRCommDataAlphaEncodingCharacters, start + 1); // characters may not necessarily be in order, so end at any letter + return str.substr(start + 1, end - (start + 1)); } -static bool argValid(std::string str, char del) { return str.find(del) != std::string::npos; } +static bool argValid(const std::string& str, const char del) { + return str.find(del) != std::string::npos; +} -VRCommData_t AlphaEncodingManager::Decode(std::string input) { - std::array flexion; - for (int i = 0; i < 5; i++) { // splay tracking not yet supported - flexion[i] = -1; // 0.5; - } +AlphaEncodingManager::AlphaEncodingManager(const float maxAnalogValue) : EncodingManager(maxAnalogValue) {} - if (argValid(input, (char)VRCommDataAlphaEncodingCharacter::FIN_THUMB)) - flexion[0] = stof(getArgumentSubstring(input, (char)VRCommDataAlphaEncodingCharacter::FIN_THUMB)) / m_maxAnalogValue; - if (argValid(input, (char)VRCommDataAlphaEncodingCharacter::FIN_INDEX)) - flexion[1] = stof(getArgumentSubstring(input, (char)VRCommDataAlphaEncodingCharacter::FIN_INDEX)) / m_maxAnalogValue; - if (argValid(input, (char)VRCommDataAlphaEncodingCharacter::FIN_MIDDLE)) - flexion[2] = stof(getArgumentSubstring(input, (char)VRCommDataAlphaEncodingCharacter::FIN_MIDDLE)) / m_maxAnalogValue; - if (argValid(input, (char)VRCommDataAlphaEncodingCharacter::FIN_RING)) - flexion[3] = stof(getArgumentSubstring(input, (char)VRCommDataAlphaEncodingCharacter::FIN_RING)) / m_maxAnalogValue; - if (argValid(input, (char)VRCommDataAlphaEncodingCharacter::FIN_PINKY)) - flexion[4] = stof(getArgumentSubstring(input, (char)VRCommDataAlphaEncodingCharacter::FIN_PINKY)) / m_maxAnalogValue; +VRInputData AlphaEncodingManager::Decode(const std::string input) { + std::array flexion = {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f}; + if (argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::FinThumb))) + flexion[0] = stof(getArgumentSubstring(input, static_cast(VRCommDataAlphaEncodingCharacter::FinThumb))) / maxAnalogValue_; + if (argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::FinIndex))) + flexion[1] = stof(getArgumentSubstring(input, static_cast(VRCommDataAlphaEncodingCharacter::FinIndex))) / maxAnalogValue_; + if (argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::FinMiddle))) + flexion[2] = stof(getArgumentSubstring(input, static_cast(VRCommDataAlphaEncodingCharacter::FinMiddle))) / maxAnalogValue_; + if (argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::FinRing))) + flexion[3] = stof(getArgumentSubstring(input, static_cast(VRCommDataAlphaEncodingCharacter::FinRing))) / maxAnalogValue_; + if (argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::FinPinky))) + flexion[4] = stof(getArgumentSubstring(input, static_cast(VRCommDataAlphaEncodingCharacter::FinPinky))) / maxAnalogValue_; float joyX = 0; float joyY = 0; + if (argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::JoyX))) + joyX = 2 * stof(getArgumentSubstring(input, static_cast(VRCommDataAlphaEncodingCharacter::JoyX))) / maxAnalogValue_ - 1; + if (argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::JoyY))) + joyY = 2 * stof(getArgumentSubstring(input, static_cast(VRCommDataAlphaEncodingCharacter::JoyY))) / maxAnalogValue_ - 1; - if (argValid(input, (char)VRCommDataAlphaEncodingCharacter::JOY_X)) - joyX = 2 * stof(getArgumentSubstring(input, (char)VRCommDataAlphaEncodingCharacter::JOY_X)) / m_maxAnalogValue - 1; - if (argValid(input, (char)VRCommDataAlphaEncodingCharacter::JOY_Y)) - joyY = 2 * stof(getArgumentSubstring(input, (char)VRCommDataAlphaEncodingCharacter::JOY_Y)) / m_maxAnalogValue - 1; - - VRCommData_t commData(flexion, joyX, joyY, argValid(input, (char)VRCommDataAlphaEncodingCharacter::JOY_BTN), - argValid(input, (char)VRCommDataAlphaEncodingCharacter::BTN_TRG), argValid(input, (char)VRCommDataAlphaEncodingCharacter::BTN_A), - argValid(input, (char)VRCommDataAlphaEncodingCharacter::BTN_B), argValid(input, (char)VRCommDataAlphaEncodingCharacter::GES_GRAB), - argValid(input, (char)VRCommDataAlphaEncodingCharacter::GES_PINCH), argValid(input, (char)VRCommDataAlphaEncodingCharacter::BTN_MENU), - argValid(input, (char)VRCommDataAlphaEncodingCharacter::BTN_CALIB)); + VRInputData inputData( + flexion, + joyX, + joyY, + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::JoyBtn)), + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::BtnTrg)), + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::BtnA)), + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::BtnB)), + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::GesGrab)), + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::GesPinch)), + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::BtnMenu)), + argValid(input, static_cast(VRCommDataAlphaEncodingCharacter::BtnCalib))); - return commData; + return inputData; } -std::string AlphaEncodingManager::Encode(const VRFFBData_t& data) { - std::string result = - string_format("%c%d%c%d%c%d%c%d%c%d\n", (char)VRCommDataAlphaEncodingCharacter::FIN_THUMB, data.thumbCurl, (char)VRCommDataAlphaEncodingCharacter::FIN_INDEX, - data.indexCurl, (char)VRCommDataAlphaEncodingCharacter::FIN_MIDDLE, data.middleCurl, (char)VRCommDataAlphaEncodingCharacter::FIN_RING, data.ringCurl, - (char)VRCommDataAlphaEncodingCharacter::FIN_PINKY, data.pinkyCurl); +std::string AlphaEncodingManager::Encode(const VRFFBData& input) { + std::string result = StringFormat( + "%c%d%c%d%c%d%c%d%c%d\n", + static_cast(VRCommDataAlphaEncodingCharacter::FinThumb), + input.thumbCurl, + static_cast(VRCommDataAlphaEncodingCharacter::FinIndex), + input.indexCurl, + static_cast(VRCommDataAlphaEncodingCharacter::FinMiddle), + input.middleCurl, + static_cast(VRCommDataAlphaEncodingCharacter::FinRing), + input.ringCurl, + static_cast(VRCommDataAlphaEncodingCharacter::FinPinky), + input.pinkyCurl); return result; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/Encode/EncodingManager.cpp b/src/Encode/EncodingManager.cpp new file mode 100644 index 00000000..bafe31e6 --- /dev/null +++ b/src/Encode/EncodingManager.cpp @@ -0,0 +1,34 @@ +#include "Encode/EncodingManager.h" + +VRFFBData::VRFFBData() : VRFFBData(0, 0, 0, 0, 0) {} + +VRFFBData::VRFFBData(const short thumbCurl, const short indexCurl, const short middleCurl, const short ringCurl, const short pinkyCurl) + : thumbCurl(thumbCurl), indexCurl(indexCurl), middleCurl(middleCurl), ringCurl(ringCurl), pinkyCurl(pinkyCurl) {} + +VRInputData::VRInputData() : VRInputData({0, 0, 0, 0, 0}, 0.0f, 0.0f, false, false, false, false, false, false, false, false) {} + +VRInputData::VRInputData( + const std::array flexion, + const float joyX, + const float joyY, + const bool joyButton, + const bool trgButton, + const bool aButton, + const bool bButton, + const bool grab, + const bool pinch, + const bool menu, + const bool calibrate) + : flexion(flexion), + joyX(joyX), + joyY(joyY), + joyButton(joyButton), + trgButton(trgButton), + aButton(aButton), + bButton(bButton), + grab(grab), + pinch(pinch), + menu(menu), + calibrate(calibrate) {} + +EncodingManager::EncodingManager(const float maxAnalogValue) : maxAnalogValue_(maxAnalogValue) {} diff --git a/src/Encode/LegacyEncodingManager.cpp b/src/Encode/LegacyEncodingManager.cpp index 2266a668..b54ecd1b 100644 --- a/src/Encode/LegacyEncodingManager.cpp +++ b/src/Encode/LegacyEncodingManager.cpp @@ -3,54 +3,62 @@ #include #include -#include "DriverLog.h" - enum class VRCommDataLegacyEncodingPosition : int { - FIN_THUMB, - FIN_INDEX, - FIN_MIDDLE, - FIN_RING, - FIN_PINKY, - JOY_X, - JOY_Y, - JOY_BTN, - BTN_TRG, - BTN_A, - BTN_B, - GES_GRAB, - GES_PINCH, - MAX, + FinThumb, + FinIndex, + FinMiddle, + FinRing, + FinPinky, + JoyX, + JoyY, + JoyBtn, + BtnTrg, + BtnA, + BtnB, + GesGrab, + GesPinch, + Max, }; -VRCommData_t LegacyEncodingManager::Decode(std::string input) { +LegacyEncodingManager::LegacyEncodingManager(const float maxAnalogValue) : EncodingManager(maxAnalogValue) {} + +VRInputData LegacyEncodingManager::Decode(const std::string input) { std::string buf; std::stringstream ss(input); - std::vector tokens((int)VRCommDataLegacyEncodingPosition::MAX); - std::fill(tokens.begin(), tokens.begin() + (int)VRCommDataLegacyEncodingPosition::MAX, 0.0f); + std::vector tokens(static_cast(VRCommDataLegacyEncodingPosition::Max), 0.0f); - short i = 0; - while (getline(ss, buf, '&')) { - tokens[i] = std::stof(buf); - i++; + uint64_t tokenI = 0; + while (tokenI < tokens.size() && getline(ss, buf, '&')) { + tokens[tokenI] = std::stof(buf); + tokenI++; } - std::array flexion; - for (int i = 0; i < 5; i++) { - flexion[i] = tokens[i] / m_maxAnalogValue; + std::array flexion{}; + for (uint8_t flexionI = 0; flexionI < 5; flexionI++) { + flexion[flexionI] = tokens[flexionI] / maxAnalogValue_; } - const float joyX = (2 * tokens[(int)VRCommDataLegacyEncodingPosition::JOY_X] / m_maxAnalogValue) - 1; - const float joyY = (2 * tokens[(int)VRCommDataLegacyEncodingPosition::JOY_Y] / m_maxAnalogValue) - 1; + const float joyX = 2 * tokens[static_cast(VRCommDataLegacyEncodingPosition::JoyX)] / maxAnalogValue_ - 1; + const float joyY = 2 * tokens[static_cast(VRCommDataLegacyEncodingPosition::JoyY)] / maxAnalogValue_ - 1; - VRCommData_t commData(flexion, joyX, joyY, tokens[(int)VRCommDataLegacyEncodingPosition::JOY_BTN] == 1, tokens[(int)VRCommDataLegacyEncodingPosition::BTN_TRG] == 1, - tokens[(int)VRCommDataLegacyEncodingPosition::BTN_A] == 1, tokens[(int)VRCommDataLegacyEncodingPosition::BTN_B] == 1, - tokens[(int)VRCommDataLegacyEncodingPosition::GES_GRAB] == 1, tokens[(int)VRCommDataLegacyEncodingPosition::GES_PINCH] == 1, false, false); + VRInputData inputData( + flexion, + joyX, + joyY, + tokens[static_cast(VRCommDataLegacyEncodingPosition::JoyBtn)] == 1, + tokens[static_cast(VRCommDataLegacyEncodingPosition::BtnTrg)] == 1, + tokens[static_cast(VRCommDataLegacyEncodingPosition::BtnA)] == 1, + tokens[static_cast(VRCommDataLegacyEncodingPosition::BtnB)] == 1, + tokens[static_cast(VRCommDataLegacyEncodingPosition::GesGrab)] == 1, + tokens[static_cast(VRCommDataLegacyEncodingPosition::GesPinch)] == 1, + false, + false); - return commData; + return inputData; } -std::string LegacyEncodingManager::Encode(const VRFFBData_t& data) { - std::string result = string_format("%d&%d&%d&%d&%d\n", data.thumbCurl, data.indexCurl, data.middleCurl, data.ringCurl, data.pinkyCurl); +std::string LegacyEncodingManager::Encode(const VRFFBData& input) { + std::string result = StringFormat("%d&%d&%d&%d&%d\n", input.thumbCurl, input.indexCurl, input.middleCurl, input.ringCurl, input.pinkyCurl); return result; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/ForceFeedback.cpp b/src/ForceFeedback.cpp index 34ff151a..74e5db22 100644 --- a/src/ForceFeedback.cpp +++ b/src/ForceFeedback.cpp @@ -1,21 +1,18 @@ #include "ForceFeedback.h" -#include +#include -#include "DriverLog.h" - -FFBListener::FFBListener(std::function callback, vr::ETrackedControllerRole role) : m_callback(callback), m_role(role) { - std::string pipeName = "\\\\.\\pipe\\vrapplication\\ffb\\curl\\"; - pipeName.append((role == vr::ETrackedControllerRole::TrackedControllerRole_RightHand) ? "right" : "left"); - m_pipe = std::make_unique(pipeName, sizeof(VRFFBData_t)); +FFBListener::FFBListener(std::function callback, const vr::ETrackedControllerRole role) + : callback_(std::move(callback)), role_(role) { + std::string pipeName = R"(\\.\pipe\vrapplication\ffb\curl\)"; + pipeName.append(role == vr::ETrackedControllerRole::TrackedControllerRole_RightHand ? "right" : "left"); + pipe_ = std::make_unique>(pipeName); }; void FFBListener::Start() { - m_pipe->Start([&](LPVOID data) { - VRFFBData_t *ffbData = (VRFFBData_t *)data; - - m_callback(*ffbData); - }); + pipe_->StartListening([&](const VRFFBData* data) { callback_(*data); }); } -void FFBListener::Stop() { m_pipe->Stop(); }; \ No newline at end of file +void FFBListener::Stop() const { + pipe_->StopListening(); +}; \ No newline at end of file diff --git a/src/Quaternion.cpp b/src/Quaternion.cpp deleted file mode 100644 index 44d6c43a..00000000 --- a/src/Quaternion.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "Quaternion.h" -#include - -double DegToRad(double degrees) { - return degrees * M_PI / 180.0; -} -double RadToDeg(double rad) { - return rad * 180.0 / M_PI; -} - -vr::HmdVector3_t GetPosition(const vr::HmdMatrix34_t& matrix) { - vr::HmdVector3_t vector{}; - - vector.v[0] = matrix.m[0][3]; - vector.v[1] = matrix.m[1][3]; - vector.v[2] = matrix.m[2][3]; - - return vector; -} - -vr::HmdVector3_t CombinePosition(const vr::HmdMatrix34_t& matrix, const vr::HmdVector3_t& vec) { - vr::HmdVector3_t vector{}; - - vector.v[0] = matrix.m[0][3] + vec.v[0]; - vector.v[1] = matrix.m[1][3] + vec.v[1]; - vector.v[2] = matrix.m[2][3] + vec.v[2]; - - return vector; -} - -vr::HmdQuaternion_t GetRotation(const vr::HmdMatrix34_t& matrix) { - vr::HmdQuaternion_t q{}; - - q.w = sqrt(fmax(0, 1 + matrix.m[0][0] + matrix.m[1][1] + matrix.m[2][2])) / 2; - q.x = sqrt(fmax(0, 1 + matrix.m[0][0] - matrix.m[1][1] - matrix.m[2][2])) / 2; - q.y = sqrt(fmax(0, 1 - matrix.m[0][0] + matrix.m[1][1] - matrix.m[2][2])) / 2; - q.z = sqrt(fmax(0, 1 - matrix.m[0][0] - matrix.m[1][1] + matrix.m[2][2])) / 2; - - q.x = copysign(q.x, matrix.m[2][1] - matrix.m[1][2]); - q.y = copysign(q.y, matrix.m[0][2] - matrix.m[2][0]); - q.z = copysign(q.z, matrix.m[1][0] - matrix.m[0][1]); - - return q; -} - -vr::HmdMatrix33_t GetRotationMatrix(const vr::HmdMatrix34_t& matrix) { - vr::HmdMatrix33_t result = { { - {matrix.m[0][0], matrix.m[0][1], matrix.m[0][2]}, - {matrix.m[1][0], matrix.m[1][1], matrix.m[1][2]}, - {matrix.m[2][0], matrix.m[2][1], matrix.m[2][2]} - } }; - - return result; -} -vr::HmdVector3_t MultiplyMatrix(const vr::HmdMatrix33_t& matrix, const vr::HmdVector3_t& vector) { - vr::HmdVector3_t result{}; - - result.v[0] = matrix.m[0][0] * vector.v[0] + matrix.m[0][1] * vector.v[1] + matrix.m[0][2] * vector.v[2]; - result.v[1] = matrix.m[1][0] * vector.v[0] + matrix.m[1][1] * vector.v[1] + matrix.m[1][2] * vector.v[2]; - result.v[2] = matrix.m[2][0] * vector.v[0] + matrix.m[2][1] * vector.v[1] + matrix.m[2][2] * vector.v[2]; - - return result; -} - -vr::HmdQuaternion_t QuaternionFromAngle(const double& xx, const double& yy, const double& zz, const double& a) { - double factor = sin(a / 2.0); - - // Calculate the x, y and z of the quaternion - double x = xx * factor; - double y = yy * factor; - double z = zz * factor; - - double w = cos(a / 2.0); - - double n = std::sqrt(x * x + y * y + z * z + w * w); - x /= n; - y /= n; - z /= n; - w /= n; - - vr::HmdQuaternion_t quat = { w,x,y,z }; - - return quat; -} - -vr::HmdMatrix33_t QuaternionToMatrix(const vr::HmdQuaternion_t q) { - - vr::HmdMatrix33_t result = { { - {(float)(1 - 2*q.y*q.y - 2*q.z*q.z), (float)(2*q.x*q.y - 2*q.z*q.w), (float)(2*q.x*q.z + 2*q.y*q.w)}, - {(float)(2*q.x*q.y + 2*q.z*q.w), (float)(1 - 2*q.x*q.x - 2 * q.z*q.z), (float)(2*q.y*q.z - 2*q.x*q.w)}, - {(float)(2*q.x*q.z - 2*q.y*q.w), (float)(2*q.y*q.z + 2*q.x*q.w), (float)(1 - 2*q.x*q.x - 2*q.y*q.y)} - } }; - - return result; -} - -double QuatNorm(const vr::HmdQuaternion_t q) { - return sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z); -} - -vr::HmdQuaternion_t QuatConjugate(const vr::HmdQuaternion_t q) { - vr::HmdQuaternion_t quat = { q.w,-q.x,-q.y,-q.z }; - return quat; -} - -vr::HmdQuaternion_t MultiplyQuaternion(const vr::HmdQuaternion_t& q, const vr::HmdQuaternion_t& r) { - vr::HmdQuaternion_t result{}; - - result.w = (r.w * q.w - r.x * q.x - r.y * q.y - r.z * q.z); - result.x = (r.w * q.x + r.x * q.w - r.y * q.z + r.z * q.y); - result.y = (r.w * q.y + r.x * q.z + r.y * q.w - r.z * q.x); - result.z = (r.w * q.z - r.x * q.y + r.y * q.x + r.z * q.w); - - return result; -} - -vr::HmdQuaternion_t EulerToQuaternion(const double& yaw, const double& pitch, const double& roll) { - // Abbreviations for the various angular functions - double cy = cos(yaw * 0.5); - double sy = sin(yaw * 0.5); - double cp = cos(pitch * 0.5); - double sp = sin(pitch * 0.5); - double cr = cos(roll * 0.5); - double sr = sin(roll * 0.5); - - vr::HmdQuaternion_t q{}; - q.w = cr * cp * cy + sr * sp * sy; - q.x = sr * cp * cy - cr * sp * sy; - q.y = cr * sp * cy + sr * cp * sy; - q.z = cr * cp * sy - sr * sp * cy; - - return q; -} -vr::HmdVector3_t QuaternionToEuler(vr::HmdQuaternion_t q) { - vr::HmdVector3_t angles{}; - - // roll (x-axis rotation) - double sinr_cosp = 2 * (q.w * q.x + q.y * q.z); - double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y); - angles.v[0] = (float)std::atan2(sinr_cosp, cosr_cosp); - - // pitch (y-axis rotation) - double sinp = 2 * (q.w * q.y - q.z * q.x); - if (std::abs(sinp) >= 1) - angles.v[1] = (float)std::copysign(M_PI / 2, sinp); // use 90 degrees if out of range - else - angles.v[1] = (float)std::asin(sinp); - - // yaw (z-axis rotation) - double siny_cosp = 2 * (q.w * q.z + q.x * q.y); - double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z); - angles.v[2] = (float)std::atan2(siny_cosp, cosy_cosp); - vr::HmdVector3_t result = { (float)RadToDeg(angles.v[2]), (float)RadToDeg(angles.v[1]), (float)RadToDeg(angles.v[0]) }; - return result; -} \ No newline at end of file diff --git a/src/Util/Logic.cpp b/src/Util/Logic.cpp new file mode 100644 index 00000000..4f4c3342 --- /dev/null +++ b/src/Util/Logic.cpp @@ -0,0 +1,16 @@ +#include "Util/Logic.h" + +#include + +bool Retry(const std::function& func, const short attempts, const short timeout) { + short retries = 0; + + do { + if (func()) return true; + std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); + + retries++; + } while (retries < attempts); + + return false; +} diff --git a/src/Util/NamedPipe.cpp b/src/Util/NamedPipe.cpp deleted file mode 100644 index a1af80ae..00000000 --- a/src/Util/NamedPipe.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "Util/NamedPipe.h" - -#include - -#include "DriverLog.h" - -static std::string GetLastErrorAsString() { - // Get the error message ID, if any. - DWORD errorMessageID = ::GetLastError(); - - if (errorMessageID == 0) { - return std::string(); // No error message has been recorded - } - - LPSTR messageBuffer = nullptr; - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); - - std::string message(messageBuffer, size); - - LocalFree(messageBuffer); - - return message; -}; - -static VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap) { - LPPIPEINST lpPipeInst; - BOOL fWrite = FALSE; - - lpPipeInst = (LPPIPEINST)lpOverLap; - - if ((dwErr == 0) && (cbBytesRead != 0)) { - lpPipeInst->callback(&lpPipeInst->chRequest); - } -}; - -NamedPipeUtil::NamedPipeUtil(std::string pipeName, size_t pipeSize) : m_pipeSize(pipeSize), m_pipeName(pipeName), m_listenerActive(false), m_hPipe(0), m_lpPipeInst(0){}; - -bool NamedPipeUtil::Start(const std::function &callback) { - m_listenerActive = true; - m_pipeThread = std::thread(&NamedPipeUtil::PipeListenerThread, this, callback); - - return true; -} - -// Returns true if pending, false if the operation has completed. -bool NamedPipeUtil::CreateAndConnectInstance(LPOVERLAPPED lpo, std::string &pipeName) { - m_hPipe = CreateNamedPipe(pipeName.c_str(), // pipe name - PIPE_ACCESS_DUPLEX | // read/write access - FILE_FLAG_OVERLAPPED, // overlapped mode - PIPE_TYPE_MESSAGE | // message-type pipe - PIPE_READMODE_MESSAGE | // message read mode - PIPE_WAIT, // blocking mode - PIPE_UNLIMITED_INSTANCES, // unlimited instances - (DWORD)m_pipeSize, // output buffer size - (DWORD)m_pipeSize, // input buffer size - 5000, // client time-out - NULL); // default security attributes - if (m_hPipe == INVALID_HANDLE_VALUE) { - DriverLog("CreateNamedPipe failed with with error: %s.\n", GetLastErrorAsString().c_str()); - return 0; - } else { - DriverLog("Pipe created successfully: %s", m_pipeName.c_str()); - } - - return ConnectToNewClient(lpo); -} - -bool NamedPipeUtil::ConnectToNewClient(LPOVERLAPPED lpo) { - BOOL fConnected, fPendingIO = FALSE; - - // Start an overlapped connection for this pipe instance. - fConnected = ConnectNamedPipe(&m_hPipe, lpo); - - if (fConnected) { - DriverLog("ConnectNamedPipe failed with %c.\n", GetLastErrorAsString().c_str()); - return 0; - } - - switch (GetLastError()) { - case ERROR_IO_PENDING: - fPendingIO = TRUE; - break; - - case ERROR_PIPE_CONNECTED: - if (SetEvent(lpo->hEvent)) break; - // fall through - default: { - DriverLog("ConnectNamedPipe failed with: %s", GetLastErrorAsString().c_str()); - return 0; - } - } - return fPendingIO; -} - -void NamedPipeUtil::PipeListenerThread(const std::function &callback) { - OVERLAPPED oConnect{}; - HANDLE hConnectEvent; - bool fPendingIO, fSuccess; - DWORD dwWait, cbRet; - hConnectEvent = CreateEvent(NULL, // default security attribute - TRUE, // manual reset event - TRUE, // initial state = signaled - NULL); // unnamed event object - - if (hConnectEvent == NULL) { - DriverLog("CreateEvent failed with with error: %s.\n", GetLastErrorAsString().c_str()); - return; - } - - oConnect.hEvent = hConnectEvent; - DriverLog("Creating pipe: %s", m_pipeName.c_str()); - - fPendingIO = CreateAndConnectInstance(&oConnect, m_pipeName); - - while (m_listenerActive) { - dwWait = WaitForSingleObjectEx(hConnectEvent, // event object to wait for - INFINITE, // waits indefinitely - TRUE); // alertable wait enabled - switch (dwWait) { - case 0: { - if (fPendingIO) { - fSuccess = GetOverlappedResult(m_hPipe, // pipe handle - &oConnect, // OVERLAPPED structure - &cbRet, // bytes transferred - FALSE); // does not wait - if (!fSuccess) { - DriverLog("ConnectNamedPipe with error: %s.\n", GetLastErrorAsString().c_str()); - return; - } - } - - m_lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST)); - - if (m_lpPipeInst == NULL) { - DriverLog("GlobalAlloc failed with error: %s.\n", GetLastErrorAsString().c_str()); - return; - } - - m_lpPipeInst->hPipeInst = m_hPipe; - - m_lpPipeInst->cbToWrite = 0; - m_lpPipeInst->callback = callback; - - bool fRead = - ReadFileEx(m_lpPipeInst->hPipeInst, &m_lpPipeInst->chRequest, (DWORD)m_pipeSize, (LPOVERLAPPED)m_lpPipeInst, (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine); - if (fRead) break; - - switch (GetLastError()) { - case ERROR_BROKEN_PIPE: - DriverLog("Detected that a client disconnected for pipe: %s", m_pipeName.c_str()); - ClosePipe(); - PipeListenerThread(callback); - break; - } - break; - } - case WAIT_IO_COMPLETION: { - break; - } - default: { - DriverLog("WaitForSingleObjectEx with error: %s.\n", GetLastErrorAsString().c_str()); - return; - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } -} - -void NamedPipeUtil::ClosePipe() { - DriverLog("Closing pipe: %s", m_pipeName.c_str()); - if (!DisconnectNamedPipe(m_lpPipeInst->hPipeInst)) { - DriverLog("DisconnectNamedPipe failed with error: %s.\n", GetLastErrorAsString().c_str()); - } - - CloseHandle(m_lpPipeInst->hPipeInst); - - // Release the storage for the pipe instance. - if (m_lpPipeInst != NULL) GlobalFree(m_lpPipeInst); -} - -void NamedPipeUtil::Stop() { - if (m_listenerActive) { - m_listenerActive = false; - m_pipeThread.join(); - ClosePipe(); - } -} - -NamedPipeUtil::~NamedPipeUtil() { Stop(); }; \ No newline at end of file diff --git a/src/Util/Quaternion.cpp b/src/Util/Quaternion.cpp new file mode 100644 index 00000000..d3628e35 --- /dev/null +++ b/src/Util/Quaternion.cpp @@ -0,0 +1,136 @@ +#include "Util/Quaternion.h" + +#include + +double DegToRad(const double degrees) { + return degrees * M_PI / 180.0; +} +double RadToDeg(const double rad) { + return rad * 180.0 / M_PI; +} + +vr::HmdVector3_t GetPosition(const vr::HmdMatrix34_t& matrix) { + vr::HmdVector3_t vector{}; + + vector.v[0] = matrix.m[0][3]; + vector.v[1] = matrix.m[1][3]; + vector.v[2] = matrix.m[2][3]; + + return vector; +} + +vr::HmdVector3_t CombinePosition(const vr::HmdMatrix34_t& matrix, const vr::HmdVector3_t& vec) { + vr::HmdVector3_t vector{}; + + vector.v[0] = matrix.m[0][3] + vec.v[0]; + vector.v[1] = matrix.m[1][3] + vec.v[1]; + vector.v[2] = matrix.m[2][3] + vec.v[2]; + + return vector; +} + +vr::HmdQuaternion_t GetRotation(const vr::HmdMatrix34_t& matrix) { + vr::HmdQuaternion_t q{}; + + q.w = sqrt(fmax(0, 1 + matrix.m[0][0] + matrix.m[1][1] + matrix.m[2][2])) / 2; + q.x = sqrt(fmax(0, 1 + matrix.m[0][0] - matrix.m[1][1] - matrix.m[2][2])) / 2; + q.y = sqrt(fmax(0, 1 - matrix.m[0][0] + matrix.m[1][1] - matrix.m[2][2])) / 2; + q.z = sqrt(fmax(0, 1 - matrix.m[0][0] - matrix.m[1][1] + matrix.m[2][2])) / 2; + + q.x = copysign(q.x, matrix.m[2][1] - matrix.m[1][2]); + q.y = copysign(q.y, matrix.m[0][2] - matrix.m[2][0]); + q.z = copysign(q.z, matrix.m[1][0] - matrix.m[0][1]); + + return q; +} + +vr::HmdMatrix33_t GetRotationMatrix(const vr::HmdMatrix34_t& matrix) { + const vr::HmdMatrix33_t result = { + {{matrix.m[0][0], matrix.m[0][1], matrix.m[0][2]}, + {matrix.m[1][0], matrix.m[1][1], matrix.m[1][2]}, + {matrix.m[2][0], matrix.m[2][1], matrix.m[2][2]}}}; + + return result; +} +vr::HmdVector3_t MultiplyMatrix(const vr::HmdMatrix33_t& matrix, const vr::HmdVector3_t& vector) { + vr::HmdVector3_t result{}; + + result.v[0] = matrix.m[0][0] * vector.v[0] + matrix.m[0][1] * vector.v[1] + matrix.m[0][2] * vector.v[2]; + result.v[1] = matrix.m[1][0] * vector.v[0] + matrix.m[1][1] * vector.v[1] + matrix.m[1][2] * vector.v[2]; + result.v[2] = matrix.m[2][0] * vector.v[0] + matrix.m[2][1] * vector.v[1] + matrix.m[2][2] * vector.v[2]; + + return result; +} + +vr::HmdMatrix33_t QuaternionToMatrix(const vr::HmdQuaternion_t& q) { + const vr::HmdMatrix33_t result = { + {{static_cast(1 - 2 * q.y * q.y - 2 * q.z * q.z), + static_cast(2 * q.x * q.y - 2 * q.z * q.w), + static_cast(2 * q.x * q.z + 2 * q.y * q.w)}, + {static_cast(2 * q.x * q.y + 2 * q.z * q.w), + static_cast(1 - 2 * q.x * q.x - 2 * q.z * q.z), + static_cast(2 * q.y * q.z - 2 * q.x * q.w)}, + {static_cast(2 * q.x * q.z - 2 * q.y * q.w), + static_cast(2 * q.y * q.z + 2 * q.x * q.w), + static_cast(1 - 2 * q.x * q.x - 2 * q.y * q.y)}}}; + + return result; +} + +vr::HmdQuaternion_t QuatConjugate(const vr::HmdQuaternion_t& q) { + const vr::HmdQuaternion_t quat = {q.w, -q.x, -q.y, -q.z}; + return quat; +} + +vr::HmdQuaternion_t MultiplyQuaternion(const vr::HmdQuaternion_t& q, const vr::HmdQuaternion_t& r) { + vr::HmdQuaternion_t result{}; + + result.w = r.w * q.w - r.x * q.x - r.y * q.y - r.z * q.z; + result.x = r.w * q.x + r.x * q.w - r.y * q.z + r.z * q.y; + result.y = r.w * q.y + r.x * q.z + r.y * q.w - r.z * q.x; + result.z = r.w * q.z - r.x * q.y + r.y * q.x + r.z * q.w; + + return result; +} + +vr::HmdQuaternion_t EulerToQuaternion(const double& yaw, const double& pitch, const double& roll) { + const double cy = cos(yaw * 0.5); + const double sy = sin(yaw * 0.5); + const double cp = cos(pitch * 0.5); + const double sp = sin(pitch * 0.5); + const double cr = cos(roll * 0.5); + const double sr = sin(roll * 0.5); + + vr::HmdQuaternion_t q{}; + q.w = cr * cp * cy + sr * sp * sy; + q.x = sr * cp * cy - cr * sp * sy; + q.y = cr * sp * cy + sr * cp * sy; + q.z = cr * cp * sy - sr * sp * cy; + + return q; +} +vr::HmdVector3_t QuaternionToEuler(const vr::HmdQuaternion_t& q) { + vr::HmdVector3_t result; + const double unit = (q.x * q.x) + (q.y * q.y) + (q.z * q.z) + (q.w * q.w); + + const float test = q.x * q.w - q.y * q.z; + + if (test > 0.4995f * unit) + { + result.v[0] = M_PI / 2; + result.v[1] = (2 * atan2(q.y / unit, q.x / unit)); + result.v[2] = 0; + } else if (test < -0.4995f * unit) + { + result.v[0] = -M_PI / 2; + result.v[1] = (-2 * atan2(q.y / unit, q.x / unit)); + result.v[2] = 0; + } else + { + result.v[0] = asin(2 * (q.w * q.x - q.y * q.z) / unit); + result.v[1] = atan2((2 / unit * q.w * q.y + 2 / unit * q.z * q.x), (1 - 2 / unit * (q.x * q.x + q.y * q.y))); + result.v[2] = atan2((2 / unit * q.w * q.z + 2 / unit * q.x * q.y), (1 - 2 / unit * (q.z * q.z + q.x * q.x))); + } + + return result; +} \ No newline at end of file diff --git a/src/Util/Windows.cpp b/src/Util/Windows.cpp index 38848c19..25f29c58 100644 --- a/src/Util/Windows.cpp +++ b/src/Util/Windows.cpp @@ -1,42 +1,63 @@ #include "Util/Windows.h" + #include + #include "DriverLog.h" EXTERN_C IMAGE_DOS_HEADER __ImageBase; -std::string GetLastErrorAsString() { - DWORD errorMessageID = ::GetLastError(); - if (errorMessageID == 0) { +std::string GetDriverPath() { + HMODULE hm = nullptr; + if (GetModuleHandleExA( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(&__ImageBase), &hm) == 0) { + DriverLog("GetModuleHandle failed, error: %s", GetLastErrorAsString().c_str()); return std::string(); } - LPSTR messageBuffer = nullptr; + char path[1024]; + if (GetModuleFileNameA(hm, path, sizeof path) == 0) { + DriverLog("GetModuleFileName failed, error: %s", GetLastErrorAsString().c_str()); + return std::string(); + } - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + auto pathString = std::string(path); + const std::string unwanted = R"(\bin\win64\)"; + return pathString.substr(0, pathString.find_last_of("\\/")).erase(pathString.find(unwanted), unwanted.length()); +} - std::string message(messageBuffer, size); +bool CreateBackgroundProcess(const std::string& path) { + STARTUPINFOA si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof si); + si.cb = sizeof si; + ZeroMemory(&pi, sizeof pi); - LocalFree(messageBuffer); + bool success = true; + if (!CreateProcess(path.c_str(), nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) success = false; - return message; + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return success; } -std::string GetDriverPath() { - char path[MAX_PATH]; - HMODULE hm = NULL; +std::string GetLastErrorAsString() { + const DWORD errorMessageId = ::GetLastError(); + if (errorMessageId == 0) return std::string(); - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)&__ImageBase, &hm) == 0) { - DriverLog("GetModuleHandle failed, error: %c", GetLastErrorAsString().c_str()); - return std::string(); - } + LPSTR messageBuffer = nullptr; + const size_t size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errorMessageId, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&messageBuffer), + 0, + nullptr); - if (GetModuleFileName(hm, path, sizeof(path)) == 0) { - DriverLog("GetModuleFileName failed, error: %c", GetLastErrorAsString().c_str()); - return std::string(); - } + std::string message(messageBuffer, size); - std::string pathString = std::string(path); - return pathString.substr(0, pathString.find_last_of("\\/")); -} + LocalFree(messageBuffer); + return message; +}