From 4c815433a0a98d413cdf0f03d01574d1c9d7b330 Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Fri, 21 May 2021 17:34:04 -0400 Subject: [PATCH 01/27] Add steam store info to readme (#82) * Add steam store info to readme * Added steam release image link --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5834d2cb..08c6b64f 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,13 @@ OpenGlove is an OpenVR driver for DIY Virtual Reality Gloves. Using OpenVR's dri ## Installation and Usage -**Download the latest on GitHub:** - * https://github.com/LucidVR/opengloves-driver/releases -**Release on Steam (Not yet available):** - * https://store.steampowered.com/app/1574050/OpenGloves - * The driver will be available on the Steam store soon. Feel free to wishlist. +### Download on Steam: +[![Steam Release](https://cdn.discordapp.com/attachments/790676300552994826/845412304219537439/openglovessteam.png)](https://store.steampowered.com/app/1574050/OpenGloves) + * We strongly recommend downloading the driver from Steam, to recieve automatic updates and UI settings. + +*Or download the latest on GitHub:* + * https://github.com/LucidVR/opengloves-driver/releases **Follow the wiki guide for configuring the driver** * https://github.com/LucidVR/opengloves-driver/wiki/Configuring-the-Driver From ab54e3aa86cb20335ea35b0bcef8eccd7d3a2c86 Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Sun, 23 May 2021 11:42:11 -0400 Subject: [PATCH 02/27] Clarify UI setting titles (#87) Some people may have been confused on what "Device Driver" meant as it didn't specify it was emulation. This PR clarifies that title and a couple other small nitpicks. --- openglove/resources/settings/default.vrsettings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openglove/resources/settings/default.vrsettings b/openglove/resources/settings/default.vrsettings index 0efecd6e..b6bc7d7a 100644 --- a/openglove/resources/settings/default.vrsettings +++ b/openglove/resources/settings/default.vrsettings @@ -4,8 +4,8 @@ "__title": "OpenGlove Configuration", "left_enabled": true, "right_enabled": true, - "communication_protocol": 0, //title:Communication Protocol - "device_driver": 1, //title: Device Driver + "communication_protocol": 0, //title:Communication Method + "device_driver": 1, //title:Device Driver Emulation "encoding_protocol": 0 //title:Encoding Protocol }, "device_lucidgloves": @@ -17,7 +17,7 @@ }, "device_knuckles": { - "__title": "Knuckle Driver", + "__title": "Knuckles Emulation", "__type": "device_driver:1", "left_serial_number": "LHR-E217CD00", "right_serial_number": "LHR-E217CD01" @@ -61,4 +61,4 @@ "__title": "Encoding Protocol", "max_analog_value": 1023 } -} \ No newline at end of file +} From f961520ad5aa5c9f9caf00642c6a01870068cd05 Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sun, 23 May 2021 18:16:54 +0100 Subject: [PATCH 03/27] Fix mingw link errors (#86) * fix incorrect syntax which wasn't caught with msvc * link winsock libraries in cmake --- CMakeLists.txt | 2 +- include/Communication/BTSerialCommunicationManager.h | 6 ------ include/ControllerPose.h | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f85334cb..7a58bc88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ add_library("${OPENGLOVE_PROJECT}" SHARED "${HEADERS}" "${SOURCES}") target_include_directories("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_INCLUDE_DIR}") target_include_directories("${OPENGLOVE_PROJECT}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/") -target_link_libraries("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_LIB}") +target_link_libraries("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_LIB}" wsock32.lib ws2_32.lib Bthprops.lib) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include" PREFIX "Header Files" FILES ${HEADERS}) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Source Files" FILES ${SOURCES}) diff --git a/include/Communication/BTSerialCommunicationManager.h b/include/Communication/BTSerialCommunicationManager.h index a1fc1d78..3c1576b2 100644 --- a/include/Communication/BTSerialCommunicationManager.h +++ b/include/Communication/BTSerialCommunicationManager.h @@ -15,13 +15,7 @@ #include #include -#ifdef _WIN32 - #pragma comment(lib, "Ws2_32.lib") - #pragma comment(lib, "Bthprops.lib") -#endif - #define ARDUINO_WAIT_TIME 1000 - class BTSerialCommunicationManager : public ICommunicationManager { public: BTSerialCommunicationManager(const VRBTSerialConfiguration_t& configuration, std::unique_ptr encodingManager); diff --git a/include/ControllerPose.h b/include/ControllerPose.h index 85e8e27e..0778a2a6 100644 --- a/include/ControllerPose.h +++ b/include/ControllerPose.h @@ -20,6 +20,6 @@ class ControllerPose { std::string m_thisDeviceManufacturer; - bool ControllerPose::IsOtherRole(int32_t test); + bool IsOtherRole(int32_t test); }; \ No newline at end of file From 451d883501234de91f7b94db2ddefba4accbdfd0 Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sun, 23 May 2021 18:17:12 +0100 Subject: [PATCH 04/27] add clang format (#89) --- .clang-format | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..7ca52308 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: Google +ColumnLimit: 100 \ No newline at end of file From 6593c28b1af73fd843210f5e7fb57e3fcc2e63bb Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Tue, 25 May 2021 14:52:28 +0100 Subject: [PATCH 05/27] Remove add to steam step (#88) * Remove add to steam step * re-add steam driver folder setup, with sidenote * move vs built tools section * Update BUILDING.md --- BUILDING.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 1a42cb3d..4c8095c4 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -20,17 +20,19 @@ Binaries are (or will) be provided in the Releases in this Repository, but if yo This should generate Visual Studio project files in the `build/` folder, which you can then compile. -# Building with Visual Studio IDE -* Open the Visual Studio project (.sln file) in the `build/` folder -* You should already have the ability to build the driver by pressing `Ctrl + Shift + B` - * The artifacts of the build will be outputted to `build/Debug/`, or `build/Release/` depending on build configuration - # Building with Visual Studio Build Tools * run a cmake build in the `build/` folder * `cmake --build . --config Release` * The artifacts of the build will be outputted to `build/Debug/`, or `build/Release/` depending on build configuration +# Building with Visual Studio IDE +* Open the Visual Studio project (.sln file) in the `build/` folder +* You should already have the ability to build the driver by pressing `Ctrl + Shift + B` + * The artifacts of the build will be outputted to `build/Debug/`, or `build/Release/` depending on build configuration + # Adding driver to Steam +**Note:** For a more streamlined debugging environment, refer to [Debugging with Visual Studio](https://github.com/LucidVR/opengloves-driver/blob/develop/BUILDING.md#debugging-with-visual-studio). +This step is for people who may not necessarily want to setup a debugging environment, or are testing release builds. * Copy the `openglove` folder into the steamvr drivers folder * Usually located `C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers` * Running SteamVR you should see the driver activate two new controllers @@ -73,7 +75,7 @@ If you want to make changes to the code and would like to use a debugger/not hav * On the first row (with the process name ``, make sure that the `Action` is set to `Do not debug`. * Add a new row (double click on the empty `Process name` underneath ``. * Add `vrserver.exe` as the process name - * Ensure that `Action` is set to `Attach Debugger`. + * Ensure that `Action` is set to `Attach Debugger`. ## Launch SteamVR when building through Visual Studio It's usually quite useful to build then automatically launch SteamVR for debugging purposes. From c039fdb0e105b99d3e37ee82da89171067a41022 Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Fri, 11 Jun 2021 08:49:48 +0100 Subject: [PATCH 06/27] Delete .editorconfig (#92) --- .editorconfig | 69 --------------------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 1ec77c84..00000000 --- a/.editorconfig +++ /dev/null @@ -1,69 +0,0 @@ -# Visual Studio generated .editorconfig file with C++ settings. -root = true - -[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}] - -# Visual C++ Code Style settings - -cpp_generate_documentation_comments = xml - -# Visual C++ Formatting settings - -cpp_indent_braces = false -cpp_indent_multi_line_relative_to = statement_begin -cpp_indent_within_parentheses = align_to_parenthesis -cpp_indent_preserve_within_parentheses = true -cpp_indent_case_contents = true -cpp_indent_case_labels = false -cpp_indent_case_contents_when_block = false -cpp_indent_lambda_braces_when_parameter = true -cpp_indent_goto_labels = one_left -cpp_indent_preprocessor = leftmost_column -cpp_indent_access_specifiers = false -cpp_indent_namespace_contents = true -cpp_indent_preserve_comments = false -cpp_new_line_before_open_brace_namespace = same_line -cpp_new_line_before_open_brace_type = same_line -cpp_new_line_before_open_brace_function = same_line -cpp_new_line_before_open_brace_block = same_line -cpp_new_line_before_open_brace_lambda = same_line -cpp_new_line_scope_braces_on_separate_lines = true -cpp_new_line_close_brace_same_line_empty_type = false -cpp_new_line_close_brace_same_line_empty_function = false -cpp_new_line_before_catch = true -cpp_new_line_before_else = true -cpp_new_line_before_while_in_do_while = false -cpp_space_before_function_open_parenthesis = remove -cpp_space_within_parameter_list_parentheses = false -cpp_space_between_empty_parameter_list_parentheses = false -cpp_space_after_keywords_in_control_flow_statements = true -cpp_space_within_control_flow_statement_parentheses = false -cpp_space_before_lambda_open_parenthesis = false -cpp_space_within_cast_parentheses = false -cpp_space_after_cast_close_parenthesis = false -cpp_space_within_expression_parentheses = false -cpp_space_before_block_open_brace = true -cpp_space_between_empty_braces = false -cpp_space_before_initializer_list_open_brace = false -cpp_space_within_initializer_list_braces = true -cpp_space_preserve_in_initializer_list = true -cpp_space_before_open_square_bracket = false -cpp_space_within_square_brackets = false -cpp_space_before_empty_square_brackets = false -cpp_space_between_empty_square_brackets = false -cpp_space_group_square_brackets = true -cpp_space_within_lambda_brackets = false -cpp_space_between_empty_lambda_brackets = false -cpp_space_before_comma = false -cpp_space_after_comma = true -cpp_space_remove_around_member_operators = true -cpp_space_before_inheritance_colon = true -cpp_space_before_constructor_colon = true -cpp_space_remove_before_semicolon = true -cpp_space_after_semicolon = true -cpp_space_remove_around_unary_operator = true -cpp_space_around_binary_operator = insert -cpp_space_around_assignment_operator = insert -cpp_space_pointer_reference_alignment = left -cpp_space_around_ternary_operator = insert -cpp_wrap_preserve_blocks = all_one_line_scopes From 711f3d96795aeebb2d6896592ee077fb055a807f Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sun, 27 Jun 2021 23:24:18 +0100 Subject: [PATCH 07/27] Controller Discovery From Overlay (#95) * controller discovery from overlay * reimplement controller id override * change overlay folder name and consistently check for new controllers * fix setting to wrong hand and fallback controllers * add debug log warning to console * capitilisation fix * typo --- .gitignore | 3 +- BUILDING.md | 12 +- CMakeLists.txt | 2 + include/ControllerDiscovery.h | 44 ++++ include/ControllerPose.h | 26 +-- libraries/asio | 1 - .../resources/settings/default.vrsettings | 4 +- overlay/CMakeLists.txt | 13 ++ overlay/main.cpp | 150 ++++++++++++ overlay/main.h | 18 ++ src/ControllerDiscovery.cpp | 204 ++++++++++++++++ src/ControllerPose.cpp | 219 +++++++----------- src/DeviceDriver/KnuckleDriver.cpp | 2 +- src/DeviceProvider.cpp | 1 + 14 files changed, 540 insertions(+), 159 deletions(-) create mode 100644 include/ControllerDiscovery.h delete mode 160000 libraries/asio create mode 100644 overlay/CMakeLists.txt create mode 100644 overlay/main.cpp create mode 100644 overlay/main.h create mode 100644 src/ControllerDiscovery.cpp diff --git a/.gitignore b/.gitignore index 1f2587be..69181b72 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ Build/ *.vcxproj.* CMakeCache.txt -cmake_install.cmake \ No newline at end of file +cmake_install.cmake +clion_build/ \ No newline at end of file diff --git a/BUILDING.md b/BUILDING.md index 4c8095c4..4bd679b1 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -77,14 +77,18 @@ If you want to make changes to the code and would like to use a debugger/not hav * Add `vrserver.exe` as the process name * Ensure that `Action` is set to `Attach Debugger`. -## Launch SteamVR when building through Visual Studio -It's usually quite useful to build then automatically launch SteamVR for debugging purposes. +## Launch SteamVR/Overlay when building through Visual Studio +It's usually quite useful to build then automatically launch SteamVR/Overlay for debugging purposes. +The project includes both a SteamVR Driver & Overlay (found in `overlay/`). Running the overlay exe automatically launches SteamVR. +The overlay is used for utilising methods that are not found in the OpenVR Driver API, such as discovering controllers. If you do not need this functionality, you can simply launch SteamVR. To launch SteamVR for debugging: * Click on the arrow next to `Local Windows Debugger` * Select `ALL_BUILD Debug Properties` * Navigate to the `Debugger` Property (under Configuration Properties) -* Set `Command` to the location of `vrstartup.exe` - * This is usually located `C:\Program Files (x86)\Steam\steamapps\common\SteamVR\bin\win64\vrstartup.exe` +* Set `Command` to the location of `vrstartup.exe` (to start just SteamVR) or the Overlay exe (to start the Ovlerlay and SteamVR). + * SteamVR's entry point (`vrstartup.exe`) is usually located `C:\Program Files (x86)\Steam\steamapps\common\SteamVR\bin\win64\vrstartup.exe` + * OpenGlove's Overlay is usually found in the build folder, `overlay\Debug\openglove_overlay.exe` + * Provide the full or relative path to the executable, such as `E:\opengloves-driver\build\overlay\Debug\openglove_overlay.exe`, or `$(solutionDir)overlay\Debug\openglove_overlay.exe` ![Debug Properties](https://cdn.discordapp.com/attachments/790676300552994826/840985376679002172/unknown.png) ![Debugging Configuration Properties](https://cdn.discordapp.com/attachments/790676300552994826/840985404202549318/unknown.png) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a58bc88..e7f4ee31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ endif() find_library(OPENVR_LIB openvr_api HINTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/openvr/lib/${PLATFORM_NAME}${PROCESSOR_ARCH}/" NO_DEFAULT_PATH ) +add_subdirectory("overlay") + set(DRIVER_NAME "openglove") set(OPENGLOVE_PROJECT "driver_${DRIVER_NAME}") diff --git a/include/ControllerDiscovery.h b/include/ControllerDiscovery.h new file mode 100644 index 00000000..0a2509f1 --- /dev/null +++ b/include/ControllerDiscovery.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include +#include +#include + +#include "openvr_driver.h" + +struct ControllerPipeData { + short controllerId; +}; +typedef struct { + OVERLAPPED oOverlap; + HANDLE hPipeInst; + ControllerPipeData chRequest; + DWORD cbRead; + DWORD cbToWrite; + std::function callback; +} PIPEINST, *LPPIPEINST; + +class ControllerDiscoveryPipe { + public: + ControllerDiscoveryPipe(); + ~ControllerDiscoveryPipe(); + + bool Start(const std::function& callback, vr::ETrackedControllerRole role); + void Stop(); + + private: + void PipeListenerThread(const std::function& callback, + vr::ETrackedControllerRole role); + void DisconnectAndClose(); + bool CreateAndConnectInstance(LPOVERLAPPED lpo, std::string& pipeName); + bool ConnectToNewClient(LPOVERLAPPED lpo); + 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/ControllerPose.h b/include/ControllerPose.h index 0778a2a6..50f5e1b6 100644 --- a/include/ControllerPose.h +++ b/include/ControllerPose.h @@ -1,25 +1,25 @@ #pragma once #include +#include #include "DeviceConfiguration.h" +#include "ControllerDiscovery.h" class ControllerPose { -public: - ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, - std::string thisDeviceManufacturer, - VRPoseConfiguration_t poseConfiguration); - vr::DriverPose_t UpdatePose(); -private: - //We may not initially know what the id of the device that we want to shadow is. This method finds devices that have a specific type specified and that are not this one - void DiscoverController(); + public: + ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, std::string thisDeviceManufacturer, + VRPoseConfiguration_t poseConfiguration); - uint32_t m_shadowControllerId = vr::k_unTrackedDeviceIndexInvalid; + vr::DriverPose_t UpdatePose(); - VRPoseConfiguration_t m_poseConfiguration; + private: + uint32_t m_shadowControllerId = vr::k_unTrackedDeviceIndexInvalid; - vr::ETrackedControllerRole m_shadowDeviceOfRole = vr::TrackedControllerRole_Invalid; + VRPoseConfiguration_t m_poseConfiguration; - std::string m_thisDeviceManufacturer; + vr::ETrackedControllerRole m_shadowDeviceOfRole = vr::TrackedControllerRole_Invalid; - bool IsOtherRole(int32_t test); + std::string m_thisDeviceManufacturer; + bool IsOtherRole(int32_t test); + std::unique_ptr m_controllerDiscoverer; }; \ No newline at end of file diff --git a/libraries/asio b/libraries/asio deleted file mode 160000 index 57577c6d..00000000 --- a/libraries/asio +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 57577c6db46a4e2de5351af2b185bf52696699a9 diff --git a/openglove/resources/settings/default.vrsettings b/openglove/resources/settings/default.vrsettings index b6bc7d7a..07bc52d5 100644 --- a/openglove/resources/settings/default.vrsettings +++ b/openglove/resources/settings/default.vrsettings @@ -28,13 +28,13 @@ "right_x_offset_position": -0.1, "right_y_offset_position": -0.08, "right_z_offset_position": -0.03, - "right_x_offset_degrees": -40, + "right_x_offset_degrees": 0, "right_y_offset_degrees": 0, "right_z_offset_degrees": 0, "left_x_offset_position": 0.1, "left_y_offset_position": -0.08, "left_z_offset_position": -0.03, - "left_x_offset_degrees": -40, + "left_x_offset_degrees": 0, "left_y_offset_degrees": 0, "left_z_offset_degrees": 0, "pose_offset": -0.01, diff --git a/overlay/CMakeLists.txt b/overlay/CMakeLists.txt new file mode 100644 index 00000000..a7a9b738 --- /dev/null +++ b/overlay/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 3.8) + + +# Add source to this project's executable. +add_executable (openglove_overlay WIN32 "main.cpp" "main.h") + +target_include_directories("openglove_overlay" PUBLIC "${OPENVR_INCLUDE_DIR}") +target_link_libraries("openglove_overlay" PUBLIC "${OPENVR_LIB}") + +add_custom_command(TARGET openglove_overlay POST_BUILD +COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${PROJECT_SOURCE_DIR}/libraries/openvr/bin/win64/openvr_api.dll" + $) \ No newline at end of file diff --git a/overlay/main.cpp b/overlay/main.cpp new file mode 100644 index 00000000..4885a6eb --- /dev/null +++ b/overlay/main.cpp @@ -0,0 +1,150 @@ +#include "main.h" + +#include +#include +#include + +std::atomic appActive = true; + +const std::string ourManufacturer = "LucasVRTech&Danwillm"; + +std::string GetLastErrorAsString() { + DWORD errorMessageID = ::GetLastError(); + if (errorMessageID == 0) { + return std::string(); + } + + 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; +} + +void GetAndSendControllerId(int id, vr::ETrackedControllerRole role) { + std::unique_ptr pipeHelper = std::make_unique(); + std::string pipeName; + + if (role == vr::ETrackedControllerRole::TrackedControllerRole_LeftHand) { + pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\left"; + } else { + pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\right"; + } + + ControllerPipeData data; + data.controllerId = id; + + pipeHelper->ConnectAndSendPipe(pipeName, data); +} + +void DiscoverController(vr::ETrackedControllerRole role) { + int lastFound = -1; + int curFound = -1; + while (appActive) { + for (int32_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)); + + std::string sThisManufacturer(thisManufacturer); + + if (ourManufacturer == sThisManufacturer) continue; + + short deviceRole = vr::VRSystem()->GetControllerRoleForTrackedDeviceIndex(i); + + if (deviceRole == role) { + curFound = i; + break; + }; + + int32_t controllerHint = vr::VRSystem()->GetInt32TrackedDeviceProperty( + i, vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32); + + if (controllerHint == role) { + curFound = i; + break; + } + } + + if (curFound != lastFound) { + GetAndSendControllerId(curFound, role); + lastFound = curFound; + } + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } +} + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { + vr::EVRInitError error; + VR_Init(&error, vr::VRApplication_Overlay); + + if (error == vr::EVRInitError::VRInitError_None) { + std::thread leftControllerThread = std::thread( + &DiscoverController, vr::ETrackedControllerRole::TrackedControllerRole_LeftHand); + + std::thread rightControllerThread = std::thread( + &DiscoverController, vr::ETrackedControllerRole::TrackedControllerRole_RightHand); + + while (appActive) { + vr::VREvent_t event; + while (vr::VRSystem() && vr::VRSystem()->PollNextEvent(&event, sizeof event)) { + switch (event.eventType) { + case vr::VREvent_Quit: + + appActive = false; + vr::VRSystem()->AcknowledgeQuit_Exiting(); + + leftControllerThread.join(); + rightControllerThread.join(); + vr::VR_Shutdown(); + return 0; + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + } else { + vr::VR_Shutdown(); + } + return 0; +} + +PipeHelper::PipeHelper() {} + +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; + + if (GetLastError() != ERROR_PIPE_BUSY) { + return -1; + } + + if (!WaitNamedPipe(pipeName.c_str(), 1000)) { + return -1; + } + } + + DWORD dwWritten; + + WriteFile(m_pipeHandle, (LPCVOID)&data, sizeof(ControllerPipeData), &dwWritten, NULL); + + CloseHandle(m_pipeHandle); + + return true; +} \ No newline at end of file diff --git a/overlay/main.h b/overlay/main.h new file mode 100644 index 00000000..9392a44d --- /dev/null +++ b/overlay/main.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +struct ControllerPipeData { + short controllerId; +}; + +class PipeHelper { + public: + PipeHelper(); + + bool ConnectAndSendPipe(const std::string& pipeName, ControllerPipeData data); + void Send(); + + private: + HANDLE m_pipeHandle; +}; \ No newline at end of file diff --git a/src/ControllerDiscovery.cpp b/src/ControllerDiscovery.cpp new file mode 100644 index 00000000..2f94a09f --- /dev/null +++ b/src/ControllerDiscovery.cpp @@ -0,0 +1,204 @@ +#include "ControllerDiscovery.h" + +#include + +#include "DriverLog.h" + +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; + + // Ask Win32 to give us the string version of that message ID. + // The parameters we pass in, tell Win32 to create the buffer that holds the message for us + // (because we don't yet know how long the message string will be). + 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); + + // Copy the error message into a std::string. + std::string message(messageBuffer, size); + + // Free the Win32's string's buffer. + LocalFree(messageBuffer); + + return message; +} + +ControllerDiscoveryPipe::ControllerDiscoveryPipe() + : m_listenerActive(false), m_hPipe(0), m_lpPipeInst(0){}; + +bool ControllerDiscoveryPipe::Start(const std::function &callback, + vr::ETrackedControllerRole role) { + m_listenerActive = true; + m_pipeThread = std::thread(&ControllerDiscoveryPipe::PipeListenerThread, this, callback, role); + + return true; +} + +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); + } +} + +// Returns true if pending, false if the operation has completed. +bool ControllerDiscoveryPipe::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 + sizeof(ControllerPipeData), // output buffer size + sizeof(ControllerPipeData), // 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 { + DebugDriverLog("Created pipe successfully"); + } + + return ConnectToNewClient(lpo); +} + +bool ControllerDiscoveryPipe::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; + default: { + DriverLog("ConnectNamedPipe failed with: %s", GetLastErrorAsString().c_str()); + return 0; + } + } + return fPendingIO; +} + +void ControllerDiscoveryPipe::PipeListenerThread( + const std::function &callback, vr::ETrackedControllerRole role) { + 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; + } + + std::string pipeName; + + if (role == vr::ETrackedControllerRole::TrackedControllerRole_LeftHand) { + pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\left"; + } else { + pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\right"; + } + DebugDriverLog("Creating pipe: %s", pipeName.c_str()); + + fPendingIO = CreateAndConnectInstance(&oConnect, 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, + sizeof(ControllerPipeData), (LPOVERLAPPED)m_lpPipeInst, + (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine); + + switch (GetLastError()) { + case ERROR_BROKEN_PIPE: + DisconnectAndClose(); + PipeListenerThread(callback, role); + 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(500)); + } +} + +void ControllerDiscoveryPipe::DisconnectAndClose() { + DebugDriverLog("Closing pipe..."); + if (m_listenerActive) m_listenerActive = false; + + if (!DisconnectNamedPipe(m_lpPipeInst->hPipeInst)) { + DebugDriverLog("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 ControllerDiscoveryPipe::Stop() { + DriverLog("Disconnecting controller pipe..."); + m_listenerActive = false; + m_pipeThread.join(); + DisconnectAndClose(); +} + +ControllerDiscoveryPipe::~ControllerDiscoveryPipe() { Stop(); }; \ No newline at end of file diff --git a/src/ControllerPose.cpp b/src/ControllerPose.cpp index 5693a5c1..8de19b51 100644 --- a/src/ControllerPose.cpp +++ b/src/ControllerPose.cpp @@ -1,152 +1,97 @@ #include "ControllerPose.h" -#include #include +#include + #include "DriverLog.h" #include "Quaternion.h" - ControllerPose::ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, std::string thisDeviceManufacturer, - VRPoseConfiguration_t poseConfiguration) : - m_shadowDeviceOfRole(shadowDeviceOfRole), - m_thisDeviceManufacturer(std::move(thisDeviceManufacturer)), - m_poseConfiguration(poseConfiguration) {} + VRPoseConfiguration_t poseConfiguration) + : m_shadowDeviceOfRole(shadowDeviceOfRole), + m_thisDeviceManufacturer(std::move(thisDeviceManufacturer)), + m_poseConfiguration(poseConfiguration) { + + + if (m_poseConfiguration.controllerOverrideEnabled) { + m_shadowControllerId = m_poseConfiguration.controllerIdOverride; + } else { + m_controllerDiscoverer = std::make_unique(); + + m_controllerDiscoverer->Start( + [&](ControllerPipeData data) { + m_shadowControllerId = data.controllerId; + DebugDriverLog("Received message! %i", data.controllerId); + }, + m_shadowDeviceOfRole); + } + +} vr::DriverPose_t ControllerPose::UpdatePose() { - vr::DriverPose_t newPose = {0}; - newPose.qWorldFromDriverRotation.w = 1; - newPose.qDriverFromHeadRotation.w = 1; - - if (m_shadowControllerId != vr::k_unTrackedDeviceIndexInvalid) { - vr::TrackedDevicePose_t trackedDevicePoses[vr::k_unMaxTrackedDeviceCount]; - vr::VRServerDriverHost()->GetRawTrackedDevicePoses(0, trackedDevicePoses, vr::k_unMaxTrackedDeviceCount); - - if (trackedDevicePoses[m_shadowControllerId].bPoseIsValid) { - - //get the matrix that represents the position of the controller that we are shadowing - vr::HmdMatrix34_t controllerMatrix = trackedDevicePoses[m_shadowControllerId].mDeviceToAbsoluteTracking; - - //get only the rotation (3x3 matrix), as the 3x4 matrix also includes position - vr::HmdMatrix33_t controllerRotationMatrix = GetRotationMatrix(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); - - //combine these positions to get the resultant position - 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); - - //Copy other values from the controller that we want for this device - newPose.vecAngularVelocity[0] = trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[0]; - newPose.vecAngularVelocity[1] = trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[1]; - newPose.vecAngularVelocity[2] = trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[2]; - - newPose.vecVelocity[0] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[0]; - newPose.vecVelocity[1] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[1]; - newPose.vecVelocity[2] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[2]; - - newPose.poseIsValid = true; - newPose.deviceIsConnected = true; - - newPose.result = vr::TrackingResult_Running_OK; - - newPose.poseTimeOffset = m_poseConfiguration.poseOffset; - } else { - newPose.poseIsValid = false; - newPose.deviceIsConnected = true; - newPose.result = vr::TrackingResult_Uninitialized; - } - + vr::DriverPose_t newPose = {0}; + newPose.qWorldFromDriverRotation.w = 1; + newPose.qDriverFromHeadRotation.w = 1; + + if (m_shadowControllerId != vr::k_unTrackedDeviceIndexInvalid) { + vr::TrackedDevicePose_t trackedDevicePoses[vr::k_unMaxTrackedDeviceCount]; + vr::VRServerDriverHost()->GetRawTrackedDevicePoses(0, trackedDevicePoses, + vr::k_unMaxTrackedDeviceCount); + + if (trackedDevicePoses[m_shadowControllerId].bPoseIsValid) { + // get the matrix that represents the position of the controller that we are shadowing + vr::HmdMatrix34_t controllerMatrix = + trackedDevicePoses[m_shadowControllerId].mDeviceToAbsoluteTracking; + + // get only the rotation (3x3 matrix), as the 3x4 matrix also includes position + vr::HmdMatrix33_t controllerRotationMatrix = GetRotationMatrix(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); + + // combine these positions to get the resultant position + 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); + + // Copy other values from the controller that we want for this device + newPose.vecAngularVelocity[0] = + trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[0]; + newPose.vecAngularVelocity[1] = + trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[1]; + newPose.vecAngularVelocity[2] = + trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[2]; + + newPose.vecVelocity[0] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[0]; + newPose.vecVelocity[1] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[1]; + newPose.vecVelocity[2] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[2]; + + newPose.poseIsValid = true; + newPose.deviceIsConnected = true; + + newPose.result = vr::TrackingResult_Running_OK; + + newPose.poseTimeOffset = m_poseConfiguration.poseOffset; } else { - newPose.result = vr::TrackingResult_Uninitialized; - newPose.deviceIsConnected = false; - DiscoverController(); + newPose.poseIsValid = false; + newPose.deviceIsConnected = true; + newPose.result = vr::TrackingResult_Uninitialized; } - return newPose; -} + } else { + newPose.result = vr::TrackingResult_Uninitialized; + newPose.deviceIsConnected = false; + } -//Checks if a role is the opposite hand from the current hand -bool ControllerPose::IsOtherRole(int32_t test) { - if (m_shadowDeviceOfRole == vr::ETrackedControllerRole::TrackedControllerRole_RightHand) - return test == vr::ETrackedControllerRole::TrackedControllerRole_LeftHand; - else - return test == vr::ETrackedControllerRole::TrackedControllerRole_RightHand; -} - -void ControllerPose::DiscoverController() { - //if there's an override, default to that - if (m_poseConfiguration.controllerOverrideEnabled) { - DriverLog("Controller ID override set to id: %i", m_poseConfiguration.controllerIdOverride); - m_shadowControllerId = m_poseConfiguration.controllerIdOverride; - return; - } - - std::priority_queue> backupDevices; - bool otherTaken = false; - - //omit id 0, as this is always the headset pose - for (int i = 1; i < vr::k_unMaxTrackedDeviceCount; i++) { - vr::ETrackedPropertyError err; - vr::PropertyContainerHandle_t container = vr::VRProperties()->TrackedDeviceToPropertyContainer(i); - std::string foundDeviceManufacturer = vr::VRProperties()->GetStringProperty(container, - vr::Prop_ManufacturerName_String, - &err); - const int32_t foundDeviceClass = vr::VRProperties()->GetInt32Property(container, vr::ETrackedDeviceProperty::Prop_DeviceClass_Int32, &err); - - int32_t foundControllerRole = vr::VRProperties()->GetInt32Property(container, - vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32, - &err); - - //make sure we're not trying to find our own controllers - if (m_thisDeviceManufacturer == foundDeviceManufacturer) continue; - - //We have a device which identifies itself as the correct role, and that device is not this one. - if (foundControllerRole == m_shadowDeviceOfRole) { - DriverLog("Discovered a %s handed controller! Id: %i, Manufacturer: %s", - m_shadowDeviceOfRole == vr::ETrackedControllerRole::TrackedControllerRole_RightHand ? "right" : "left", - i, foundDeviceManufacturer.c_str()); - m_shadowControllerId = i; - return; - } - //If this belongs to the other hand, then skip it - else if (IsOtherRole(foundControllerRole)) { - otherTaken = true; - continue; - } - //otherwise fill backup - switch (foundDeviceClass) { - case vr::ETrackedDeviceClass::TrackedDeviceClass_Controller: - backupDevices.push(std::make_pair(2, i)); //this is a generic controller like a vive wand - break; - case vr::ETrackedDeviceClass::TrackedDeviceClass_GenericTracker: - backupDevices.push(std::make_pair(1, i)); //this is a generic tracker - break; - /*default: - backupDevices.push(std::make_pair(0, i)); //currently not considering other devices - */ - } - } - - //If we haven't already picked something, use the backup - if (!backupDevices.empty()) { - m_shadowControllerId = backupDevices.top().second; - DriverLog("Selected a controller/tracker from backup. Id: %i, Priority: %i", m_shadowControllerId, backupDevices.top().first); - vr::ETrackedPropertyError err; - vr::PropertyContainerHandle_t container = vr::VRProperties()->TrackedDeviceToPropertyContainer(m_shadowControllerId); - /* - * There really needs to be a better way to ensure we're attached to the right generic controller, - * but unfortunately we have not found a practical solution for this yet which works with vive wands. :( - */ - vr::VRProperties()->SetInt32Property(container, vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32, m_shadowDeviceOfRole); - } - //else - //DebugDriverLog("No suitable devices to attach to!");// + return newPose; } \ No newline at end of file diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index d8a6e38e..83e29014 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -5,7 +5,7 @@ #include "DriverLog.h" namespace knuckleDevice { - const char* c_deviceManufacturer = "FluidControlObject"; + const char* c_deviceManufacturer = "LucasVRTech&Danwillm"; } enum ComponentIndex : int { diff --git a/src/DeviceProvider.cpp b/src/DeviceProvider.cpp index c1df91c0..9d1d39a2 100644 --- a/src/DeviceProvider.cpp +++ b/src/DeviceProvider.cpp @@ -14,6 +14,7 @@ vr::EVRInitError DeviceProvider::Init(vr::IVRDriverContext* pDriverContext) { VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext); InitDriverLog(vr::VRDriverLog()); + DebugDriverLog("openglove is running in DEBUG mode"); VRDeviceConfiguration_t leftConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_LeftHand); VRDeviceConfiguration_t rightConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_RightHand); From ad1a731374ef42e3a004245e66d3961457be03da Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Sun, 27 Jun 2021 18:31:05 -0400 Subject: [PATCH 08/27] Alphabetic Encoding Manager (#96) * Add alpha encoding manager for analog values * Add buttons into alpha-encoding * Double sided joystick values * AlphaEncodingManager set in DeviceProvider * Fix runtime errors * Add Alpha Encoding into default.vrsettings * Requested changes, includes, headers, default setting * header fix --- include/DeviceConfiguration.h | 1 + include/DeviceProvider.h | 3 - include/Encode/AlphaEncodingManager.h | 16 ++++ .../resources/settings/default.vrsettings | 19 +++-- src/DeviceProvider.cpp | 20 +++-- src/Encode/AlphaEncodingManager.cpp | 85 +++++++++++++++++++ 6 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 include/Encode/AlphaEncodingManager.h create mode 100644 src/Encode/AlphaEncodingManager.cpp diff --git a/include/DeviceConfiguration.h b/include/DeviceConfiguration.h index 4cc28dc5..dd8906f2 100644 --- a/include/DeviceConfiguration.h +++ b/include/DeviceConfiguration.h @@ -15,6 +15,7 @@ enum VRCommunicationProtocol { enum VREncodingProtocol { LEGACY = 0, + ALPHA = 1, }; enum VRDeviceDriver { diff --git a/include/DeviceProvider.h b/include/DeviceProvider.h index 5ee814e5..adad5eb7 100644 --- a/include/DeviceProvider.h +++ b/include/DeviceProvider.h @@ -9,11 +9,8 @@ #include "DriverLog.h" #include "Communication/CommunicationManager.h" -#include "Communication/SerialCommunicationManager.h" -#include "Communication/BTSerialCommunicationManager.h" #include "Encode/EncodingManager.h" -#include "Encode/LegacyEncodingManager.h" #include "DeviceDriver/DeviceDriver.h" diff --git a/include/Encode/AlphaEncodingManager.h b/include/Encode/AlphaEncodingManager.h new file mode 100644 index 00000000..6eb966d1 --- /dev/null +++ b/include/Encode/AlphaEncodingManager.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Encode/EncodingManager.h" + +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); +private: + std::string getArgumentSubstring(std::string str, char del); + + float m_maxAnalogValue; + const char* alphabet = "ABCDEFGHIJKLM"; // expand as more letters are added to manager +}; \ No newline at end of file diff --git a/openglove/resources/settings/default.vrsettings b/openglove/resources/settings/default.vrsettings index 07bc52d5..9f48044c 100644 --- a/openglove/resources/settings/default.vrsettings +++ b/openglove/resources/settings/default.vrsettings @@ -6,7 +6,7 @@ "right_enabled": true, "communication_protocol": 0, //title:Communication Method "device_driver": 1, //title:Device Driver Emulation - "encoding_protocol": 0 //title:Encoding Protocol + "encoding_protocol": 1 //title:Encoding Protocol }, "device_lucidgloves": { @@ -49,16 +49,23 @@ "left_port": "\\\\.\\COM4", "right_port": "\\\\.\\COM5" }, - "communication_btserial": { + "communication_btserial": + { "__type": "communication_protocol:1", "__title": "Bluetooth Serial", - "left_name": "lucidgloves-left", - "right_name": "lucidgloves-right" - }, + "left_name": "lucidgloves-left", + "right_name": "lucidgloves-right" + }, "encoding_legacy": { "__type": "encoding_protocol: 0", - "__title": "Encoding Protocol", + "__title": "Legacy Encoding", + "max_analog_value": 1023 + }, + "encoding_alpha": + { + "__type": "encoding_protocol: 1", + "__title": "Alpha Protocol", "max_analog_value": 1023 } } diff --git a/src/DeviceProvider.cpp b/src/DeviceProvider.cpp index 9d1d39a2..2f2c7cf9 100644 --- a/src/DeviceProvider.cpp +++ b/src/DeviceProvider.cpp @@ -5,6 +5,10 @@ #include "DeviceDriver/KnuckleDriver.h" #include "Communication/SerialCommunicationManager.h" +#include "Communication/BTSerialCommunicationManager.h" + +#include "Encode/LegacyEncodingManager.h" +#include "Encode/AlphaEncodingManager.h" #include "Quaternion.h" @@ -37,14 +41,20 @@ std::unique_ptr DeviceProvider::InstantiateDeviceDriver(VRDeviceC std::unique_ptr encodingManager; bool isRightHand = configuration.role == vr::TrackedControllerRole_RightHand; - switch (configuration.encodingProtocol) { default: DriverLog("No encoding protocol set. Using legacy."); - case VREncodingProtocol::LEGACY: - const int maxAnalogValue = vr::VRSettings()->GetInt32("encoding_legacy", "max_analog_value"); - encodingManager = std::make_unique(maxAnalogValue); - break; + case VREncodingProtocol::LEGACY: { + const int maxAnalogValue = + vr::VRSettings()->GetInt32("encoding_legacy", "max_analog_value"); + encodingManager = std::make_unique(maxAnalogValue); + break; + } + case VREncodingProtocol::ALPHA: { + const int maxAnalogValue = vr::VRSettings()->GetInt32("encoding_alpha", "max_analog_value");// + encodingManager = std::make_unique(maxAnalogValue); + break; + } } diff --git a/src/Encode/AlphaEncodingManager.cpp b/src/Encode/AlphaEncodingManager.cpp new file mode 100644 index 00000000..71dc9404 --- /dev/null +++ b/src/Encode/AlphaEncodingManager.cpp @@ -0,0 +1,85 @@ +#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 +*Alpha Encoding Manager Arguments: +* A - Pinky Finger Position +* B - Ring Finger Position +* C - Middle Finger Position +* D - Index Finger Position +* E - Thumb Finger Position +* F - Joystick X +* G - Joystick Y +* H - Joystick click +* I - Trigger button +* J - A button +* K - B button +* L - Grab button +* M - Pinch button +* - Calibration Reset button +* +*/ + +std::string AlphaEncodingManager::getArgumentSubstring(std::string str, char del) { + int start = str.find(del); + if (start == std::string::npos) + return NULL; + int end = str.find_first_of(alphabet, start + 1); //characters may not necessarily be in order, so end at any letter + return str.substr(start, end - start); +} + +bool argValid(std::string str, char del) { return str.find(del) != std::string::npos; } + +VRCommData_t AlphaEncodingManager::Decode(std::string input) { + + std::array flexion; + std::array splay; + + for (int i = 0; i < 5; i++) { //splay tracking not yet supported + flexion[i] = -1; // 0.5; + splay[i] = 0.5; + } + + if (argValid(input, 'A')) + flexion[0] = + stof(getArgumentSubstring(input, 'A').substr(1, std::string::npos)) / m_maxAnalogValue; + if (argValid(input, 'B')) + flexion[1] = + stof(getArgumentSubstring(input, 'B').substr(1, std::string::npos)) / m_maxAnalogValue; + if (argValid(input, 'C')) + flexion[2] = + stof(getArgumentSubstring(input, 'C').substr(1, std::string::npos)) / m_maxAnalogValue; + if (argValid(input, 'D')) + flexion[3] = + stof(getArgumentSubstring(input, 'D').substr(1, std::string::npos)) / m_maxAnalogValue; + if (argValid(input, 'E')) + flexion[4] = + stof(getArgumentSubstring(input, 'E').substr(1, std::string::npos)) / m_maxAnalogValue; + + float joyX = 0; + float joyY = 0; + + if (argValid(input, 'F')) + joyX = 2 * stof(getArgumentSubstring(input, 'E').substr(1, std::string::npos)) / m_maxAnalogValue - 1; + if (argValid(input, 'G')) + joyY = 2 * stof(getArgumentSubstring(input, 'G').substr(1, std::string::npos)) / m_maxAnalogValue - 1; + + VRCommData_t commData( + flexion, + splay, + joyX, + joyY, + argValid(input, 'H'), //joystick click + argValid(input, 'I'), //trigger + argValid(input, 'J'), //A button + argValid(input, 'K'), //B button + argValid(input, 'L'), //grab + argValid(input, 'M') //pinch + ); + + return commData; +} \ No newline at end of file From 14574b478cc557c36adb0d0179341a211f7939ca Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Fri, 2 Jul 2021 07:15:53 -0400 Subject: [PATCH 09/27] Readme naming consistencies (#98) OpenGlove -> OpenGloves Discord Server -> Community Discord Server --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 08c6b64f..7092d4f3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# OpenGlove Driver +# OpenGloves Driver -OpenGlove is an OpenVR driver for DIY Virtual Reality Gloves. Using OpenVR's driver interface we are able to provide support for many SteamVR/OpenVR games. +OpenGloves is an OpenVR driver for DIY Virtual Reality Gloves. Using OpenVR's driver interface we are able to provide support for many SteamVR/OpenVR games. ## Installation and Usage @@ -18,7 +18,7 @@ OpenGlove is an OpenVR driver for DIY Virtual Reality Gloves. Using OpenVR's dri **Problems?** * Check [Troubleshooting](https://github.com/LucidVR/opengloves-driver/wiki/Troubleshooting) - * Didn't help? Contact us on the [Discord Server](https://discord.com/invite/Y6XTvnHDUC) + * Didn't help? Contact us on the [Community Discord Server](https://discord.com/invite/Y6XTvnHDUC) ## Building If you want to use the driver as-is, refer to [Installation and Usage](#Installation-and-Usage). If you are planning on modifying source files, refer to [BUILDING.md](https://github.com/LucidVR/opengloves-driver/blob/develop/BUILDING.md). From 71dbeea7ed0ee8d9264fec4c799bc12bb7d59e79 Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Sun, 4 Jul 2021 14:35:59 -0400 Subject: [PATCH 10/27] Fix overlay vive trackers (#101) Vive trackers now working properly with controller discovery through overlay. Now also checking for tracker and controller type before assigning an ID to the device as well. --- overlay/main.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/overlay/main.cpp b/overlay/main.cpp index 4885a6eb..c191365a 100644 --- a/overlay/main.cpp +++ b/overlay/main.cpp @@ -47,6 +47,7 @@ void GetAndSendControllerId(int id, vr::ETrackedControllerRole role) { void DiscoverController(vr::ETrackedControllerRole role) { int lastFound = -1; int curFound = -1; + while (appActive) { for (int32_t i = 1; i < vr::k_unMaxTrackedDeviceCount; i++) { char thisManufacturer[1024]; @@ -60,11 +61,6 @@ void DiscoverController(vr::ETrackedControllerRole role) { short deviceRole = vr::VRSystem()->GetControllerRoleForTrackedDeviceIndex(i); - if (deviceRole == role) { - curFound = i; - break; - }; - int32_t controllerHint = vr::VRSystem()->GetInt32TrackedDeviceProperty( i, vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32); @@ -72,6 +68,17 @@ void DiscoverController(vr::ETrackedControllerRole role) { curFound = i; break; } + + 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; + } + } + } if (curFound != lastFound) { From ae7574c4359996c92772257cd8c1550b592ab8ed Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Sun, 4 Jul 2021 23:06:14 -0400 Subject: [PATCH 11/27] Automatic pose calibration (#99) - User holds a button/flips a switch on their arduino to start calibration - In-game hand gets stuck in a fixed place, user can move their IRL hand independently of the in-game hand - User lines up their IRL hand to where the in-game hand is (either using partial passthrough, or the relative position of the controller compared to the hand to line it up) - User ends calibration by flipping the switch with their other hand - Driver takes the pose of the in game hand, and the pose of the controller, and compares them - Quaternion offset calculated using inverse multiplication - Position offset calculated with a simple subtraction and then multiplied by inverse matrix - Driver updates the pose used by ControllerPose, and returns normal hand tracking - Driver saves new pose settings to default.vrsettings by calling `vr::VRSettings()->SetFloat()` * Start structure in ControllerPose * Rotation offsets now imported as floats * Add Quaternion Inverse, Conjugate, Norm * Calculate Transform Quaternion * Add QuaternionToMatrix * Fix quaternionToMatrix * Calculate offset vector * Add input to begin and end calibration with a button press * Fix alpha encoding to stop at new button presses * Beginnings of working calibration * Move logic to GetControllerPose() * Auto calibration for position now fully working * Automatic Calibration now FULLY WORKING! * Add QuaternionToAngle * VR pose settings now updated through VRSettings * Remove redundant m_isRightHand, other requested changes * Add move calibration logic to its own class * Fix crash caused by bad controller id * ControllerPose updates configuration based on calibration * Fix conversions between Euler and Quaternion * Velocity changes now in StartCalibration * Use M_PI in QuaternionToEuler --- include/Calibration.h | 23 ++++++ include/ControllerPose.h | 15 ++++ include/Encode/AlphaEncodingManager.h | 2 +- include/Encode/EncodingManager.h | 6 +- include/Quaternion.h | 8 ++ libraries/asio | 1 + .../resources/settings/default.vrsettings | 12 +-- src/Calibration.cpp | 74 ++++++++++++++++++ src/ControllerPose.cpp | 60 +++++++++++---- src/DeviceDriver/KnuckleDriver.cpp | 10 +++ src/DeviceProvider.cpp | 6 +- src/Encode/AlphaEncodingManager.cpp | 3 +- src/Encode/LegacyEncodingManager.cpp | 3 +- src/Quaternion.cpp | 77 ++++++++++++++----- 14 files changed, 248 insertions(+), 52 deletions(-) create mode 100644 include/Calibration.h create mode 160000 libraries/asio create mode 100644 src/Calibration.cpp diff --git a/include/Calibration.h b/include/Calibration.h new file mode 100644 index 00000000..f0fcd346 --- /dev/null +++ b/include/Calibration.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include "DeviceConfiguration.h" + +class Calibration { +public: + Calibration(); + + void StartCalibration(vr::DriverPose_t maintainPose); + + VRPoseConfiguration_t FinishCalibration(vr::TrackedDevicePose_t controllerPose, VRPoseConfiguration_t poseConfiguration, bool isRightHand); + + void CancelCalibration(); + + bool isCalibrating(); + + vr::DriverPose_t GetMaintainPose(); + +private: + vr::DriverPose_t m_maintainPose; + bool m_isCalibrating = false; +}; \ No newline at end of file diff --git a/include/ControllerPose.h b/include/ControllerPose.h index 50f5e1b6..3cab840e 100644 --- a/include/ControllerPose.h +++ b/include/ControllerPose.h @@ -3,6 +3,7 @@ #include #include "DeviceConfiguration.h" #include "ControllerDiscovery.h" +#include "Calibration.h" class ControllerPose { public: @@ -11,6 +12,14 @@ class ControllerPose { vr::DriverPose_t UpdatePose(); + void StartCalibration(); + + void FinishCalibration(); + + void CancelCalibration(); + + bool isCalibrating(); + private: uint32_t m_shadowControllerId = vr::k_unTrackedDeviceIndexInvalid; @@ -20,6 +29,12 @@ class ControllerPose { std::string m_thisDeviceManufacturer; + vr::TrackedDevicePose_t GetControllerPose(); + bool IsOtherRole(int32_t test); + + bool isRightHand(); + std::unique_ptr m_controllerDiscoverer; + std::unique_ptr m_calibration; }; \ No newline at end of file diff --git a/include/Encode/AlphaEncodingManager.h b/include/Encode/AlphaEncodingManager.h index 6eb966d1..69277854 100644 --- a/include/Encode/AlphaEncodingManager.h +++ b/include/Encode/AlphaEncodingManager.h @@ -12,5 +12,5 @@ class AlphaEncodingManager : public IEncodingManager { std::string getArgumentSubstring(std::string str, char del); float m_maxAnalogValue; - const char* alphabet = "ABCDEFGHIJKLM"; // expand as more letters are added to manager + const char* alphabet = "ABCDEFGHIJKLMNO"; // expand as more letters are added to manager }; \ No newline at end of file diff --git a/include/Encode/EncodingManager.h b/include/Encode/EncodingManager.h index 39c0fae3..70e900db 100644 --- a/include/Encode/EncodingManager.h +++ b/include/Encode/EncodingManager.h @@ -3,7 +3,7 @@ #include struct VRCommData_t { - VRCommData_t(std::array flexion, std::array splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch) : + VRCommData_t(std::array flexion, std::array splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool calibrate) : flexion(flexion), splay(splay), joyX(joyX), @@ -13,7 +13,8 @@ struct VRCommData_t { aButton(aButton), bButton(bButton), grab(grab), - pinch(pinch) {}; + pinch(pinch), + calibrate(calibrate){}; std::array flexion; std::array splay; @@ -25,6 +26,7 @@ struct VRCommData_t { bool bButton; bool grab; bool pinch; + bool calibrate; }; enum VRCommDataInputPosition { diff --git a/include/Quaternion.h b/include/Quaternion.h index 03804ea6..2a7e0ecf 100644 --- a/include/Quaternion.h +++ b/include/Quaternion.h @@ -5,6 +5,8 @@ double DegToRad(int degrees); double RadToDeg(double rad); + + //get the quaternion for roation from a matrix vr::HmdQuaternion_t GetRotation(const vr::HmdMatrix34_t& matrix); vr::HmdVector3_t GetPosition(const vr::HmdMatrix34_t& matrix); @@ -17,3 +19,9 @@ vr::HmdQuaternion_t QuaternionFromAngle(const double& xx, const double& yy, cons vr::HmdQuaternion_t EulerToQuaternion(const double& x, const double& y, const double& z); 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); + +double QuatNorm(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 diff --git a/libraries/asio b/libraries/asio new file mode 160000 index 00000000..57577c6d --- /dev/null +++ b/libraries/asio @@ -0,0 +1 @@ +Subproject commit 57577c6db46a4e2de5351af2b185bf52696699a9 diff --git a/openglove/resources/settings/default.vrsettings b/openglove/resources/settings/default.vrsettings index 9f48044c..fea8d2bc 100644 --- a/openglove/resources/settings/default.vrsettings +++ b/openglove/resources/settings/default.vrsettings @@ -28,15 +28,15 @@ "right_x_offset_position": -0.1, "right_y_offset_position": -0.08, "right_z_offset_position": -0.03, - "right_x_offset_degrees": 0, - "right_y_offset_degrees": 0, - "right_z_offset_degrees": 0, + "right_x_offset_degrees": 0.0, + "right_y_offset_degrees": 0.0, + "right_z_offset_degrees": 0.0, "left_x_offset_position": 0.1, "left_y_offset_position": -0.08, "left_z_offset_position": -0.03, - "left_x_offset_degrees": 0, - "left_y_offset_degrees": 0, - "left_z_offset_degrees": 0, + "left_x_offset_degrees": 0.0, + "left_y_offset_degrees": 0.0, + "left_z_offset_degrees": 0.0, "pose_offset": -0.01, "controller_override": false, "controller_override_left": 3, diff --git a/src/Calibration.cpp b/src/Calibration.cpp new file mode 100644 index 00000000..1502f0eb --- /dev/null +++ b/src/Calibration.cpp @@ -0,0 +1,74 @@ +#include "Calibration.h" + +#include +#include + +#include "DriverLog.h" +#include "Quaternion.h" + +Calibration::Calibration() { + 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; +} + +VRPoseConfiguration_t Calibration::FinishCalibration(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; + + vr::HmdQuaternion_t controllerQuat = GetRotation(controllerMatrix); + vr::HmdQuaternion_t handQuat = m_maintainPose.qRotation; + + + //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; + + vr::HmdVector3_t differenceVector = { m_maintainPose.vecPosition[0] - controllerMatrix.m[0][3], + m_maintainPose.vecPosition[1] - controllerMatrix.m[1][3], + m_maintainPose.vecPosition[2] - controllerMatrix.m[2][3] }; + + vr::HmdQuaternion_t transformInverse = QuatConjugate(controllerQuat); + vr::HmdMatrix33_t transformMatrix = QuaternionToMatrix(transformInverse); + vr::HmdVector3_t transformVector = MultiplyMatrix(transformMatrix, differenceVector); + + poseConfiguration.offsetVector = transformVector; + + 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]); + + vr::HmdVector3_t eulerOffset = QuaternionToEuler(transformQuat); + + 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]); + + return poseConfiguration; +} + +void Calibration::CancelCalibration() { m_isCalibrating = false; } + +bool Calibration::isCalibrating() { + return m_isCalibrating; +} + +vr::DriverPose_t Calibration::GetMaintainPose() { + return m_maintainPose; +} + diff --git a/src/ControllerPose.cpp b/src/ControllerPose.cpp index 8de19b51..5efe296b 100644 --- a/src/ControllerPose.cpp +++ b/src/ControllerPose.cpp @@ -13,7 +13,6 @@ ControllerPose::ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, m_thisDeviceManufacturer(std::move(thisDeviceManufacturer)), m_poseConfiguration(poseConfiguration) { - if (m_poseConfiguration.controllerOverrideEnabled) { m_shadowControllerId = m_poseConfiguration.controllerIdOverride; } else { @@ -26,23 +25,30 @@ ControllerPose::ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, }, m_shadowDeviceOfRole); } - + m_calibration = std::make_unique(); +} + +vr::TrackedDevicePose_t ControllerPose::GetControllerPose() { + vr::TrackedDevicePose_t trackedDevicePoses[vr::k_unMaxTrackedDeviceCount]; + vr::VRServerDriverHost()->GetRawTrackedDevicePoses(0, trackedDevicePoses, + vr::k_unMaxTrackedDeviceCount); + return trackedDevicePoses[m_shadowControllerId]; } vr::DriverPose_t ControllerPose::UpdatePose() { + if (m_calibration->isCalibrating()) + return m_calibration->GetMaintainPose(); + vr::DriverPose_t newPose = {0}; newPose.qWorldFromDriverRotation.w = 1; newPose.qDriverFromHeadRotation.w = 1; if (m_shadowControllerId != vr::k_unTrackedDeviceIndexInvalid) { - vr::TrackedDevicePose_t trackedDevicePoses[vr::k_unMaxTrackedDeviceCount]; - vr::VRServerDriverHost()->GetRawTrackedDevicePoses(0, trackedDevicePoses, - vr::k_unMaxTrackedDeviceCount); + vr::TrackedDevicePose_t controllerPose = GetControllerPose(); - if (trackedDevicePoses[m_shadowControllerId].bPoseIsValid) { + if (controllerPose.bPoseIsValid) { // get the matrix that represents the position of the controller that we are shadowing - vr::HmdMatrix34_t controllerMatrix = - trackedDevicePoses[m_shadowControllerId].mDeviceToAbsoluteTracking; + 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); @@ -65,16 +71,13 @@ vr::DriverPose_t ControllerPose::UpdatePose() { m_poseConfiguration.angleOffsetQuaternion); // Copy other values from the controller that we want for this device - newPose.vecAngularVelocity[0] = - trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[0]; - newPose.vecAngularVelocity[1] = - trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[1]; - newPose.vecAngularVelocity[2] = - trackedDevicePoses[m_shadowControllerId].vAngularVelocity.v[2]; + newPose.vecAngularVelocity[0] = controllerPose.vAngularVelocity.v[0]; + newPose.vecAngularVelocity[1] = controllerPose.vAngularVelocity.v[1]; + newPose.vecAngularVelocity[2] = controllerPose.vAngularVelocity.v[2]; - newPose.vecVelocity[0] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[0]; - newPose.vecVelocity[1] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[1]; - newPose.vecVelocity[2] = trackedDevicePoses[m_shadowControllerId].vVelocity.v[2]; + newPose.vecVelocity[0] = controllerPose.vVelocity.v[0]; + newPose.vecVelocity[1] = controllerPose.vVelocity.v[1]; + newPose.vecVelocity[2] = controllerPose.vVelocity.v[2]; newPose.poseIsValid = true; newPose.deviceIsConnected = true; @@ -94,4 +97,27 @@ vr::DriverPose_t ControllerPose::UpdatePose() { } return newPose; +} + +void ControllerPose::StartCalibration() { + m_calibration->StartCalibration(UpdatePose()); +} + +void ControllerPose::FinishCalibration() { + if (m_shadowControllerId == vr::k_unTrackedDeviceIndexInvalid) { + DebugDriverLog("Index invalid"); + CancelCalibration(); + return; + } + m_poseConfiguration = m_calibration->FinishCalibration(GetControllerPose(), m_poseConfiguration, isRightHand()); +} + +void ControllerPose::CancelCalibration() { m_calibration->CancelCalibration(); } + +bool ControllerPose::isCalibrating() { + return m_calibration->isCalibrating(); +} + +bool ControllerPose::isRightHand() { + return m_shadowDeviceOfRole == vr::TrackedControllerRole_RightHand; } \ No newline at end of file diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index 83e29014..932de007 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -211,6 +211,16 @@ void KnuckleDeviceDriver::StartDevice() { 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->FinishCalibration(); + } } catch (const std::exception& e) { DebugDriverLog("Exception caught while parsing comm data"); diff --git a/src/DeviceProvider.cpp b/src/DeviceProvider.cpp index 2f2c7cf9..62b71ace 100644 --- a/src/DeviceProvider.cpp +++ b/src/DeviceProvider.cpp @@ -116,9 +116,9 @@ VRDeviceConfiguration_t DeviceProvider::GetDeviceConfiguration(vr::ETrackedContr 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 int offsetXRot = vr::VRSettings()->GetInt32(c_poseSettingsSection, isRightHand ? "right_x_offset_degrees" : "left_x_offset_degrees"); - const int offsetYRot = vr::VRSettings()->GetInt32(c_poseSettingsSection, isRightHand ? "right_y_offset_degrees" : "left_y_offset_degrees"); - const int offsetZRot = vr::VRSettings()->GetInt32(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; diff --git a/src/Encode/AlphaEncodingManager.cpp b/src/Encode/AlphaEncodingManager.cpp index 71dc9404..a75c1393 100644 --- a/src/Encode/AlphaEncodingManager.cpp +++ b/src/Encode/AlphaEncodingManager.cpp @@ -78,7 +78,8 @@ VRCommData_t AlphaEncodingManager::Decode(std::string input) { argValid(input, 'J'), //A button argValid(input, 'K'), //B button argValid(input, 'L'), //grab - argValid(input, 'M') //pinch + argValid(input, 'M'), //pinch + argValid(input, 'O') //calibration (N reserved for menu btn) ); return commData; diff --git a/src/Encode/LegacyEncodingManager.cpp b/src/Encode/LegacyEncodingManager.cpp index 4783bf76..0c7224b7 100644 --- a/src/Encode/LegacyEncodingManager.cpp +++ b/src/Encode/LegacyEncodingManager.cpp @@ -38,7 +38,8 @@ VRCommData_t LegacyEncodingManager::Decode(std::string input) { tokens[VRCommDataInputPosition::BTN_A] == 1, tokens[VRCommDataInputPosition::BTN_B] == 1, tokens[VRCommDataInputPosition::GES_GRAB] == 1, - tokens[VRCommDataInputPosition::GES_PINCH] == 1 + tokens[VRCommDataInputPosition::GES_PINCH] == 1, + false ); return commData; diff --git a/src/Quaternion.cpp b/src/Quaternion.cpp index 0d26feb9..90afcf8f 100644 --- a/src/Quaternion.cpp +++ b/src/Quaternion.cpp @@ -83,31 +83,26 @@ vr::HmdQuaternion_t QuaternionFromAngle(const double& xx, const double& yy, cons return quat; } -//Adapted from libGDX -vr::HmdQuaternion_t EulerToQuaternion(const double& yaw, const double& pitch, const double& roll) { - vr::HmdQuaternion_t result; +vr::HmdMatrix33_t QuaternionToMatrix(const vr::HmdQuaternion_t q) { - double hr = roll * 0.5f; - double shr = sin(hr); - double chr = cos(hr); - double hp = pitch * 0.5f; - double shp = sin(hp); - double chp = cos(hp); - double hy = yaw * 0.5f; - double shy = sin(hy); - double chy = cos(hy); - double chy_shp = chy * shp; - double shy_chp = shy * chp; - double chy_chp = chy * chp; - double shy_shp = shy * shp; - - result.x = (chy_shp * chr) + (shy_chp * shr); - result.y = (shy_chp * chr) - (chy_shp * shr); - result.z = (chy_chp * shr) - (shy_shp * chr); - result.w = (chy_chp * chr) + (shy_shp * shr); + vr::HmdMatrix33_t result = { { + {1 - 2*q.y*q.y - 2*q.z*q.z, 2*q.x*q.y - 2*q.z*q.w, 2*q.x*q.z + 2*q.y*q.w}, + {2*q.x*q.y + 2*q.z*q.w, 1 - 2*q.x*q.x - 2 * q.z*q.z, 2*q.y*q.z - 2*q.x*q.w}, + {2*q.x*q.z - 2*q.y*q.w, 2*q.y*q.z + 2*q.x*q.w, 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; @@ -116,5 +111,45 @@ vr::HmdQuaternion_t MultiplyQuaternion(const vr::HmdQuaternion_t& q, const vr::H 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] = 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] = std::copysign(M_PI / 2, sinp); // use 90 degrees if out of range + else + angles.v[1] = 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] = std::atan2(siny_cosp, cosy_cosp); + vr::HmdVector3_t result = { RadToDeg(angles.v[2]), RadToDeg(angles.v[1]), RadToDeg(angles.v[0]) }; return result; } \ No newline at end of file From 1766e6ba66186f06fb3ef52d013195cea399866f Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Tue, 6 Jul 2021 19:37:50 +0100 Subject: [PATCH 12/27] remove lighthouse tracking system name from knuckles emulation (#102) --- src/DeviceDriver/KnuckleDriver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index 932de007..b7ed2036 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -69,7 +69,6 @@ vr::EVRInitError KnuckleDeviceDriver::Activate(uint32_t unObjectId) { 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); - vr::VRProperties()->SetStringProperty(props, vr::Prop_TrackingSystemName_String, "lighthouse"); 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); From 3b59be4bcce4505fd1e50c7e79e9169464993b3b Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Fri, 9 Jul 2021 08:48:23 -0400 Subject: [PATCH 13/27] Fix joystick for alpha encoding manager (#103) Thanks to Twidge for beta testing this bugfix. --- src/Encode/AlphaEncodingManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Encode/AlphaEncodingManager.cpp b/src/Encode/AlphaEncodingManager.cpp index a75c1393..8d117d6c 100644 --- a/src/Encode/AlphaEncodingManager.cpp +++ b/src/Encode/AlphaEncodingManager.cpp @@ -64,7 +64,7 @@ VRCommData_t AlphaEncodingManager::Decode(std::string input) { float joyY = 0; if (argValid(input, 'F')) - joyX = 2 * stof(getArgumentSubstring(input, 'E').substr(1, std::string::npos)) / m_maxAnalogValue - 1; + joyX = 2 * stof(getArgumentSubstring(input, 'F').substr(1, std::string::npos)) / m_maxAnalogValue - 1; if (argValid(input, 'G')) joyY = 2 * stof(getArgumentSubstring(input, 'G').substr(1, std::string::npos)) / m_maxAnalogValue - 1; From 63572eb488957d611a8cb53527d31b9f715ff13d Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sun, 11 Jul 2021 15:53:27 +0100 Subject: [PATCH 14/27] Init overlay/background process via driver (#105) * init overlay/background process via driver * add error --- CMakeLists.txt | 9 + include/DeviceProvider.h | 101 ++++---- openglove/bin/win64/DLL GOES HERE.txt | 0 overlay/main.cpp | 2 +- src/DeviceProvider.cpp | 322 ++++++++++++++++---------- 5 files changed, 256 insertions(+), 178 deletions(-) delete mode 100644 openglove/bin/win64/DLL GOES HERE.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e7f4ee31..c7dddd4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include" PREFIX "Header Files" FI source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Source Files" FILES ${SOURCES}) set_property(TARGET "${OPENGLOVE_PROJECT}" PROPERTY CXX_STANDARD 17) + # Copy driver assets to output folder add_custom_command( TARGET ${OPENGLOVE_PROJECT} @@ -60,4 +61,12 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy $ $/${DRIVER_NAME}/bin/${PLATFORM_NAME}${PROCESSOR_ARCH}/$ +) + +add_custom_command( + TARGET ${OPENGLOVE_PROJECT} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + $ + $/${DRIVER_NAME}/bin/${PLATFORM_NAME}${PROCESSOR_ARCH} ) \ No newline at end of file diff --git a/include/DeviceProvider.h b/include/DeviceProvider.h index adad5eb7..9c682ca2 100644 --- a/include/DeviceProvider.h +++ b/include/DeviceProvider.h @@ -4,16 +4,14 @@ #define _WINSOCKAPI_ #include + #include -#include "DeviceConfiguration.h" -#include "DriverLog.h" #include "Communication/CommunicationManager.h" - -#include "Encode/EncodingManager.h" - +#include "DeviceConfiguration.h" #include "DeviceDriver/DeviceDriver.h" - +#include "DriverLog.h" +#include "Encode/EncodingManager.h" /** This class instantiates all the device drivers you have, meaning if you've @@ -24,50 +22,49 @@ Take a look at the comment blocks for all the methods in IServerTrackedDevicePro too. **/ class DeviceProvider : public vr::IServerTrackedDeviceProvider { -public: - - /** - Initiailze and add your drivers to OpenVR here. - **/ - vr::EVRInitError Init(vr::IVRDriverContext* pDriverContext); - - /** - Called right before your driver is unloaded. - **/ - void Cleanup(); - - /** - Returns version of the openVR interface this driver works with. - **/ - const char* const* GetInterfaceVersions(); - - /** - Called every frame. Update your drivers here. - **/ - void RunFrame(); - - /** - Return true if standby mode should be blocked. False otherwise. - **/ - bool ShouldBlockStandbyMode(); - - /** - Called when OpenVR goes into stand-by mode, so you can tell your devices to go into stand-by mode - **/ - void EnterStandby(); - - /** - Called when OpenVR leaves stand-by mode. - **/ - void LeaveStandby(); - -private: - std::unique_ptr m_leftHand; - std::unique_ptr m_rightHand; - /** - * returns the configuration set in VRSettings for the device role given - **/ - VRDeviceConfiguration_t GetDeviceConfiguration(vr::ETrackedControllerRole role); - - std::unique_ptr InstantiateDeviceDriver(VRDeviceConfiguration_t configuration); + public: + /** + Initiailze and add your drivers to OpenVR here. + **/ + vr::EVRInitError Init(vr::IVRDriverContext* pDriverContext); + + /** + Called right before your driver is unloaded. + **/ + void Cleanup(); + + /** + Returns version of the openVR interface this driver works with. + **/ + const char* const* GetInterfaceVersions(); + + /** + Called every frame. Update your drivers here. + **/ + void RunFrame(); + + /** + Return true if standby mode should be blocked. False otherwise. + **/ + bool ShouldBlockStandbyMode(); + + /** + Called when OpenVR goes into stand-by mode, so you can tell your devices to go into stand-by mode + **/ + void EnterStandby(); + + /** + Called when OpenVR leaves stand-by mode. + **/ + void LeaveStandby(); + + private: + std::unique_ptr m_leftHand; + std::unique_ptr m_rightHand; + /** + * returns the configuration set in VRSettings for the device role given + **/ + VRDeviceConfiguration_t GetDeviceConfiguration(vr::ETrackedControllerRole role); + + std::unique_ptr InstantiateDeviceDriver(VRDeviceConfiguration_t configuration); }; \ No newline at end of file diff --git a/openglove/bin/win64/DLL GOES HERE.txt b/openglove/bin/win64/DLL GOES HERE.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/overlay/main.cpp b/overlay/main.cpp index c191365a..0c05966a 100644 --- a/overlay/main.cpp +++ b/overlay/main.cpp @@ -91,7 +91,7 @@ void DiscoverController(vr::ETrackedControllerRole role) { int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { vr::EVRInitError error; - VR_Init(&error, vr::VRApplication_Overlay); + VR_Init(&error, vr::VRApplication_Background); if (error == vr::EVRInitError::VRInitError_None) { std::thread leftControllerThread = std::thread( diff --git a/src/DeviceProvider.cpp b/src/DeviceProvider.cpp index 62b71ace..60b74ebf 100644 --- a/src/DeviceProvider.cpp +++ b/src/DeviceProvider.cpp @@ -1,153 +1,225 @@ #include -#include "DriverLog.h" +#include -#include "DeviceDriver/LucidGloveDriver.h" -#include "DeviceDriver/KnuckleDriver.h" +#include -#include "Communication/SerialCommunicationManager.h" #include "Communication/BTSerialCommunicationManager.h" - -#include "Encode/LegacyEncodingManager.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" -vr::EVRInitError DeviceProvider::Init(vr::IVRDriverContext* pDriverContext) { - vr::EVRInitError initError = InitServerDriverContext(pDriverContext); - if (initError != vr::EVRInitError::VRInitError_None) return initError; - - VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext); - InitDriverLog(vr::VRDriverLog()); - DebugDriverLog("openglove is running in DEBUG mode"); - - VRDeviceConfiguration_t leftConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_LeftHand); - VRDeviceConfiguration_t rightConfiguration = GetDeviceConfiguration(vr::TrackedControllerRole_RightHand); - - if (leftConfiguration.enabled) { - m_leftHand = InstantiateDeviceDriver(leftConfiguration); - vr::VRServerDriverHost()->TrackedDeviceAdded(m_leftHand->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_leftHand.get()); - } - if (rightConfiguration.enabled) { - m_rightHand = InstantiateDeviceDriver(rightConfiguration); - vr::VRServerDriverHost()->TrackedDeviceAdded(m_rightHand->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_rightHand.get()); - } - - return vr::VRInitError_None; +EXTERN_C IMAGE_DOS_HEADER __ImageBase; + +std::string GetDriverPath() { + char path[MAX_PATH]; + HMODULE hm = NULL; + + if (GetModuleHandleEx( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCSTR)&__ImageBase, &hm) == 0) { + int ret = GetLastError(); + fprintf(stderr, "GetModuleHandle failed, error = %d\n", ret); + // Return or however you want to handle an error. + } + if (GetModuleFileName(hm, path, sizeof(path)) == 0) { + int ret = GetLastError(); + fprintf(stderr, "GetModuleFileName failed, error = %d\n", ret); + // Return or however you want to handle an error. + } + + std::string::size_type pos = std::string(path).find_last_of("\\/"); + return std::string(path).substr(0, pos); } -std::unique_ptr DeviceProvider::InstantiateDeviceDriver(VRDeviceConfiguration_t configuration) { +bool CreateBackgroundProcess() { + STARTUPINFOA si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); - std::unique_ptr communicationManager; - std::unique_ptr encodingManager; + const std::string driverPath = GetDriverPath(); + DriverLog("Path to DLL: %s", driverPath.c_str()); - bool isRightHand = configuration.role == vr::TrackedControllerRole_RightHand; - switch (configuration.encodingProtocol) { - default: - DriverLog("No encoding protocol set. Using legacy."); - case VREncodingProtocol::LEGACY: { - const int maxAnalogValue = - vr::VRSettings()->GetInt32("encoding_legacy", "max_analog_value"); - encodingManager = std::make_unique(maxAnalogValue); - break; - } - case VREncodingProtocol::ALPHA: { - const int maxAnalogValue = vr::VRSettings()->GetInt32("encoding_alpha", "max_analog_value");// - encodingManager = std::make_unique(maxAnalogValue); - break; - } - } - - - - switch (configuration.communicationProtocol) { - case VRCommunicationProtocol::BTSERIAL: - { - DriverLog("Communication set to BTSerial"); - char name[248]; - vr::VRSettings()->GetString("communication_btserial", isRightHand ? "right_name" : "left_name", name, sizeof(name)); - VRBTSerialConfiguration_t btSerialSettings(name); - communicationManager = std::make_unique(btSerialSettings, std::move(encodingManager)); - break; - } - default: - DriverLog("No communication protocol set. Using serial."); - case VRCommunicationProtocol::SERIAL: - char port[16]; - vr::VRSettings()->GetString("communication_serial", isRightHand ? "right_port" : "left_port", port, sizeof(port)); - VRSerialConfiguration_t serialSettings(port); - - communicationManager = std::make_unique(serialSettings, std::move(encodingManager)); - break; - } - - switch (configuration.deviceDriver) { - case VRDeviceDriver::EMULATED_KNUCKLES: - { - char serialNumber[32]; - vr::VRSettings()->GetString("device_knuckles", isRightHand ? "right_serial_number" : "left_serial_number", serialNumber, sizeof(serialNumber)); - - return std::make_unique(configuration, std::move(communicationManager), serialNumber); - } - - default: - DriverLog("No device driver selected. Using lucidgloves."); - case VRDeviceDriver::LUCIDGLOVES: - { - char serialNumber[32]; - vr::VRSettings()->GetString("device_lucidgloves", isRightHand ? "right_serial_number" : "left_serial_number", serialNumber, sizeof(serialNumber)); - - return std::make_unique(configuration, std::move(communicationManager), serialNumber); - } - } + std::string path = driverPath + "\\openglove_overlay.exe"; -} -VRDeviceConfiguration_t DeviceProvider::GetDeviceConfiguration(vr::ETrackedControllerRole role) { - const bool isRightHand = role == vr::TrackedControllerRole_RightHand; - - const bool isEnabled = vr::VRSettings()->GetBool(c_driverSettingsSection, isRightHand ? "right_enabled" : "left_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 float poseOffset = vr::VRSettings()->GetFloat(c_poseSettingsSection, "pose_offset"); + bool success = true; + if (!CreateProcess(path.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) success = false; - 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"); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); - 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; - - const vr::HmdVector3_t offsetVector = {offsetXPos, offsetYPos, offsetZPos}; + return success; +} - //Convert the rotation to a quaternion - const vr::HmdQuaternion_t angleOffsetQuaternion = EulerToQuaternion(DegToRad(offsetXRot), DegToRad(offsetYRot), DegToRad(offsetZRot)); +vr::EVRInitError DeviceProvider::Init(vr::IVRDriverContext* pDriverContext) { + vr::EVRInitError initError = InitServerDriverContext(pDriverContext); + if (initError != vr::EVRInitError::VRInitError_None) return initError; + + VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext); + InitDriverLog(vr::VRDriverLog()); + DebugDriverLog("OpenGlove is running in DEBUG mode"); + + if (!CreateBackgroundProcess()) { + DriverLog("Could not create background process"); + return vr::VRInitError_Init_FileNotFound; + } + + VRDeviceConfiguration_t leftConfiguration = + GetDeviceConfiguration(vr::TrackedControllerRole_LeftHand); + VRDeviceConfiguration_t rightConfiguration = + GetDeviceConfiguration(vr::TrackedControllerRole_RightHand); + + if (leftConfiguration.enabled) { + m_leftHand = InstantiateDeviceDriver(leftConfiguration); + vr::VRServerDriverHost()->TrackedDeviceAdded( + m_leftHand->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_leftHand.get()); + } + if (rightConfiguration.enabled) { + m_rightHand = InstantiateDeviceDriver(rightConfiguration); + vr::VRServerDriverHost()->TrackedDeviceAdded(m_rightHand->GetSerialNumber().c_str(), + vr::TrackedDeviceClass_Controller, + m_rightHand.get()); + } + + return vr::VRInitError_None; +} - return VRDeviceConfiguration_t(role, isEnabled, VRPoseConfiguration_t(offsetVector, angleOffsetQuaternion, poseOffset, controllerOverrideEnabled, controllerIdOverride), encodingProtocol, communicationProtocol, deviceDriver); +std::unique_ptr DeviceProvider::InstantiateDeviceDriver( + VRDeviceConfiguration_t configuration) { + std::unique_ptr communicationManager; + std::unique_ptr encodingManager; + bool isRightHand = configuration.role == vr::TrackedControllerRole_RightHand; + switch (configuration.encodingProtocol) { + default: + DriverLog("No encoding protocol set. Using legacy."); + case VREncodingProtocol::LEGACY: { + const int maxAnalogValue = vr::VRSettings()->GetInt32("encoding_legacy", "max_analog_value"); + encodingManager = std::make_unique(maxAnalogValue); + break; + } + case VREncodingProtocol::ALPHA: { + const int maxAnalogValue = + vr::VRSettings()->GetInt32("encoding_alpha", "max_analog_value"); // + encodingManager = std::make_unique(maxAnalogValue); + break; + } + } + + switch (configuration.communicationProtocol) { + case VRCommunicationProtocol::BTSERIAL: { + DriverLog("Communication set to BTSerial"); + char name[248]; + vr::VRSettings()->GetString("communication_btserial", + isRightHand ? "right_name" : "left_name", name, sizeof(name)); + VRBTSerialConfiguration_t btSerialSettings(name); + communicationManager = std::make_unique( + btSerialSettings, std::move(encodingManager)); + break; + } + default: + DriverLog("No communication protocol set. Using serial."); + case VRCommunicationProtocol::SERIAL: + char port[16]; + vr::VRSettings()->GetString("communication_serial", isRightHand ? "right_port" : "left_port", + port, sizeof(port)); + VRSerialConfiguration_t serialSettings(port); + + communicationManager = + std::make_unique(serialSettings, std::move(encodingManager)); + break; + } + + switch (configuration.deviceDriver) { + case VRDeviceDriver::EMULATED_KNUCKLES: { + char serialNumber[32]; + vr::VRSettings()->GetString("device_knuckles", + isRightHand ? "right_serial_number" : "left_serial_number", + serialNumber, sizeof(serialNumber)); + + return std::make_unique(configuration, std::move(communicationManager), + serialNumber); + } + + default: + DriverLog("No device driver selected. Using lucidgloves."); + case VRDeviceDriver::LUCIDGLOVES: { + char serialNumber[32]; + vr::VRSettings()->GetString("device_lucidgloves", + isRightHand ? "right_serial_number" : "left_serial_number", + serialNumber, sizeof(serialNumber)); + + return std::make_unique( + configuration, std::move(communicationManager), serialNumber); + } + } +} +VRDeviceConfiguration_t DeviceProvider::GetDeviceConfiguration(vr::ETrackedControllerRole role) { + const bool isRightHand = role == vr::TrackedControllerRole_RightHand; + + const bool isEnabled = vr::VRSettings()->GetBool(c_driverSettingsSection, + isRightHand ? "right_enabled" : "left_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 float poseOffset = vr::VRSettings()->GetFloat(c_poseSettingsSection, "pose_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 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; + + 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, poseOffset, + controllerOverrideEnabled, controllerIdOverride), + 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 (m_leftHand && m_leftHand->IsActive()) m_leftHand->RunFrame(); + if (m_rightHand && m_rightHand->IsActive()) m_rightHand->RunFrame(); } -bool DeviceProvider::ShouldBlockStandbyMode() { - return false; -} +bool DeviceProvider::ShouldBlockStandbyMode() { return false; } void DeviceProvider::EnterStandby() {} From ed38171d5fad04c90f5fa84a1cc9e2f41bca0c7d Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Sun, 11 Jul 2021 10:54:20 -0400 Subject: [PATCH 15/27] Update discord link to static link (#104) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7092d4f3..4197ea3d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ OpenGloves is an OpenVR driver for DIY Virtual Reality Gloves. Using OpenVR's dr **Problems?** * Check [Troubleshooting](https://github.com/LucidVR/opengloves-driver/wiki/Troubleshooting) - * Didn't help? Contact us on the [Community Discord Server](https://discord.com/invite/Y6XTvnHDUC) + * Didn't help? Contact us on the [Community Discord Server](https://discord.com/invite/lucidvr) ## Building If you want to use the driver as-is, refer to [Installation and Usage](#Installation-and-Usage). If you are planning on modifying source files, refer to [BUILDING.md](https://github.com/LucidVR/opengloves-driver/blob/develop/BUILDING.md). From 6ff4992c9b3704d0acba334bb308ea44179a86df Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Wed, 21 Jul 2021 13:13:00 +0100 Subject: [PATCH 16/27] Update discord link (#106) * Update discord link * Update README.md * make https Co-authored-by: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4197ea3d..8be222ec 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ OpenGloves is an OpenVR driver for DIY Virtual Reality Gloves. Using OpenVR's dr **Problems?** * Check [Troubleshooting](https://github.com/LucidVR/opengloves-driver/wiki/Troubleshooting) - * Didn't help? Contact us on the [Community Discord Server](https://discord.com/invite/lucidvr) + * Didn't help? Contact us on the [Community Discord Server](https://discord.gg/lucidvr) ## Building If you want to use the driver as-is, refer to [Installation and Usage](#Installation-and-Usage). If you are planning on modifying source files, refer to [BUILDING.md](https://github.com/LucidVR/opengloves-driver/blob/develop/BUILDING.md). @@ -57,4 +57,4 @@ Pull requests are very welcome. For major changes, please open an issue first to * Lucas VRTech (`LucidVR#0001`) ## Discord -https://discord.gg/RjV9T8jN2G +https://discord.gg/lucidvr From 534252d73db651f411d224e48542ee96089b5343 Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Wed, 21 Jul 2021 15:07:59 -0400 Subject: [PATCH 17/27] pose_offset -> pose_time_offset (#107) --- include/DeviceConfiguration.h | 6 +++--- openglove/resources/settings/default.vrsettings | 2 +- src/ControllerPose.cpp | 2 +- src/DeviceProvider.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/DeviceConfiguration.h b/include/DeviceConfiguration.h index dd8906f2..1d84fb33 100644 --- a/include/DeviceConfiguration.h +++ b/include/DeviceConfiguration.h @@ -36,16 +36,16 @@ struct VRBTSerialConfiguration_t { }; struct VRPoseConfiguration_t { - VRPoseConfiguration_t(vr::HmdVector3_t offsetVector, vr::HmdQuaternion_t angleOffsetQuaternion, float poseOffset, + VRPoseConfiguration_t(vr::HmdVector3_t offsetVector, vr::HmdQuaternion_t angleOffsetQuaternion, float poseTimeOffset, bool controllerOverrideEnabled, int controllerIdOverride) : offsetVector(offsetVector), angleOffsetQuaternion(angleOffsetQuaternion), - poseOffset(poseOffset), + poseTimeOffset(poseTimeOffset), controllerOverrideEnabled(controllerOverrideEnabled), controllerIdOverride(controllerIdOverride) {}; vr::HmdVector3_t offsetVector; vr::HmdQuaternion_t angleOffsetQuaternion; - float poseOffset; + float poseTimeOffset; int controllerIdOverride; bool controllerOverrideEnabled; }; diff --git a/openglove/resources/settings/default.vrsettings b/openglove/resources/settings/default.vrsettings index fea8d2bc..eae066b3 100644 --- a/openglove/resources/settings/default.vrsettings +++ b/openglove/resources/settings/default.vrsettings @@ -37,7 +37,7 @@ "left_x_offset_degrees": 0.0, "left_y_offset_degrees": 0.0, "left_z_offset_degrees": 0.0, - "pose_offset": -0.01, + "pose_time_offset": -0.01, "controller_override": false, "controller_override_left": 3, "controller_override_right": 4 diff --git a/src/ControllerPose.cpp b/src/ControllerPose.cpp index 5efe296b..fd9509bf 100644 --- a/src/ControllerPose.cpp +++ b/src/ControllerPose.cpp @@ -84,7 +84,7 @@ vr::DriverPose_t ControllerPose::UpdatePose() { newPose.result = vr::TrackingResult_Running_OK; - newPose.poseTimeOffset = m_poseConfiguration.poseOffset; + newPose.poseTimeOffset = m_poseConfiguration.poseTimeOffset; } else { newPose.poseIsValid = false; newPose.deviceIsConnected = true; diff --git a/src/DeviceProvider.cpp b/src/DeviceProvider.cpp index 60b74ebf..6d740bff 100644 --- a/src/DeviceProvider.cpp +++ b/src/DeviceProvider.cpp @@ -172,7 +172,7 @@ VRDeviceConfiguration_t DeviceProvider::GetDeviceConfiguration(vr::ETrackedContr const auto deviceDriver = (VRDeviceDriver)vr::VRSettings()->GetInt32(c_driverSettingsSection, "device_driver"); - const float poseOffset = vr::VRSettings()->GetFloat(c_poseSettingsSection, "pose_offset"); + 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"); @@ -205,7 +205,7 @@ VRDeviceConfiguration_t DeviceProvider::GetDeviceConfiguration(vr::ETrackedContr return VRDeviceConfiguration_t( role, isEnabled, - VRPoseConfiguration_t(offsetVector, angleOffsetQuaternion, poseOffset, + VRPoseConfiguration_t(offsetVector, angleOffsetQuaternion, poseTimeOffset, controllerOverrideEnabled, controllerIdOverride), encodingProtocol, communicationProtocol, deviceDriver); } From ae5ea853675567df6817676ed7b0e1c81f65bfef Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sat, 24 Jul 2021 09:32:29 +0100 Subject: [PATCH 18/27] Force Feedback (#91) * add named pipe communication * add serial write for force feedback, change pipe name * Rename types in FFBPipe.h to prevent redefinition error * Add Encode into AlphaEncodingManager * Temporary fix for redefinitions * Lower pipe sleep time * Bluetooth for force feedback haptics * Fix force feedback working with bluetooth * remove unneeded switch * potential fix for disconnecting gracefully Co-authored-by: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> --- .clang-format | 2 +- .../BTSerialCommunicationManager.h | 88 ++-- include/Communication/CommunicationManager.h | 18 +- .../SerialCommunicationManager.h | 83 ++-- include/DeviceDriver/KnuckleDriver.h | 60 +-- include/Encode/AlphaEncodingManager.h | 4 +- include/Encode/EncodingManager.h | 41 +- include/Encode/LegacyEncodingManager.h | 17 +- include/ForceFeedback/FFBPipe.h | 49 +++ include/Pipe.h | 8 + src/Bones.cpp | 381 +++++++++--------- .../BTSerialCommunicationManager.cpp | 352 ++++++++-------- .../SerialCommunicationManager.cpp | 255 ++++++------ src/ControllerDiscovery.cpp | 11 +- src/DeviceDriver/KnuckleDriver.cpp | 193 +++++---- src/Encode/AlphaEncodingManager.cpp | 20 +- src/Encode/LegacyEncodingManager.cpp | 57 ++- src/ForceFeedback/FFBPipe.cpp | 214 ++++++++++ src/Pipe.cpp | 40 ++ 19 files changed, 1123 insertions(+), 770 deletions(-) create mode 100644 include/ForceFeedback/FFBPipe.h create mode 100644 include/Pipe.h create mode 100644 src/ForceFeedback/FFBPipe.cpp create mode 100644 src/Pipe.cpp diff --git a/.clang-format b/.clang-format index 7ca52308..989c047e 100644 --- a/.clang-format +++ b/.clang-format @@ -1,2 +1,2 @@ BasedOnStyle: Google -ColumnLimit: 100 \ No newline at end of file +ColumnLimit: 170 \ No newline at end of file diff --git a/include/Communication/BTSerialCommunicationManager.h b/include/Communication/BTSerialCommunicationManager.h index 3c1576b2..82960e61 100644 --- a/include/Communication/BTSerialCommunicationManager.h +++ b/include/Communication/BTSerialCommunicationManager.h @@ -1,53 +1,59 @@ #pragma once +#include -#include "CommunicationManager.h" -#include "DeviceConfiguration.h" -#include -#include #include #include -#include +#include #include +#include +#include +#include + +#include "CommunicationManager.h" +#include "DeviceConfiguration.h" #include "DriverLog.h" -#include -#include -#include + +#include +#include #include -#include + #define ARDUINO_WAIT_TIME 1000 class BTSerialCommunicationManager : public ICommunicationManager { -public: - BTSerialCommunicationManager(const VRBTSerialConfiguration_t& configuration, std::unique_ptr encodingManager); - //connect to the device using serial - void Connect(); - //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(); -private: - void ListenerThread(const std::function& callback); - bool ReceiveNextPacket(std::string &buff); - bool PurgeBuffer(); - bool getPairedEsp32BtAddress(); - bool startupWindowsSocket(); - bool connectToEsp32(); - bool sendMessageToEsp32(); - - bool m_isConnected; - std::atomic m_threadActive; - std::thread m_serialThread; - - std::unique_ptr m_encodingManager; - - VRBTSerialConfiguration_t m_btSerialConfiguration; - - BTH_ADDR m_esp32BtAddress; - SOCKADDR_BTH m_btSocketAddress; - SOCKET m_btClientSocket; - WCHAR* m_wcDeviceName; - //std::unique_ptr m_wcDeviceName; + public: + BTSerialCommunicationManager(const VRBTSerialConfiguration_t& configuration, std::unique_ptr encodingManager); + // connect to the device using serial + void Connect(); + // 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(); + + void QueueSend(const VRFFBData_t& data); + + private: + void ListenerThread(const std::function& callback); + bool ReceiveNextPacket(std::string& buff); + bool getPairedEsp32BtAddress(); + bool startupWindowsSocket(); + bool connectToEsp32(); + bool sendMessageToEsp32(); + bool m_isConnected; + std::atomic m_threadActive; + std::thread m_serialThread; + + std::unique_ptr m_encodingManager; + + VRBTSerialConfiguration_t m_btSerialConfiguration; + + BTH_ADDR m_esp32BtAddress; + SOCKADDR_BTH m_btSocketAddress; + SOCKET m_btClientSocket; + WCHAR* m_wcDeviceName; + + std::mutex m_writeMutex; + std::string m_writeString = "\n"; }; \ No newline at end of file diff --git a/include/Communication/CommunicationManager.h b/include/Communication/CommunicationManager.h index bdb2d054..b291cc4e 100644 --- a/include/Communication/CommunicationManager.h +++ b/include/Communication/CommunicationManager.h @@ -1,14 +1,18 @@ #pragma once #include #include + #include "Encode/EncodingManager.h" class ICommunicationManager { -public: - virtual void Connect() = 0; - virtual void BeginListener(const std::function& callback) = 0; - virtual bool IsConnected() = 0; - virtual void Disconnect() = 0; -private: - std::unique_ptr m_encodingManager; + public: + virtual void Connect() = 0; + virtual void BeginListener(const std::function& callback) = 0; + virtual bool IsConnected() = 0; + virtual void Disconnect() = 0; + + virtual void QueueSend(const VRFFBData_t& data) = 0; + + private: + std::unique_ptr m_encodingManager; }; \ No newline at end of file diff --git a/include/Communication/SerialCommunicationManager.h b/include/Communication/SerialCommunicationManager.h index 81e73e0e..97e1ca69 100644 --- a/include/Communication/SerialCommunicationManager.h +++ b/include/Communication/SerialCommunicationManager.h @@ -1,43 +1,64 @@ #pragma once -#include "CommunicationManager.h" -#include "DeviceConfiguration.h" #include + +#include #include #include +#include #include -#include +#include "CommunicationManager.h" +#include "DeviceConfiguration.h" #define ARDUINO_WAIT_TIME 1000 class SerialCommunicationManager : public ICommunicationManager { -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) {}; - //connect to the device using serial - void Connect(); - //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(); -private: - void ListenerThread(const std::function& callback); - bool ReceiveNextPacket(std::string &buff); - bool PurgeBuffer(); - - 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; - - std::unique_ptr m_encodingManager; + 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); + + m_writeString = m_encodingManager->Encode(data); + }; + // connect to the device using serial + void Connect(); + // 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(); + + void QueueSend(const VRFFBData_t& data); + + private: + void ListenerThread(const std::function& callback); + bool ReceiveNextPacket(std::string& buff); + bool PurgeBuffer(); + bool Write(); + + 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; + + std::unique_ptr m_encodingManager; + + std::mutex m_writeMutex; + + std::string m_writeString; }; \ No newline at end of file diff --git a/include/DeviceDriver/KnuckleDriver.h b/include/DeviceDriver/KnuckleDriver.h index 475f6653..cd578506 100644 --- a/include/DeviceDriver/KnuckleDriver.h +++ b/include/DeviceDriver/KnuckleDriver.h @@ -1,50 +1,52 @@ #pragma once #pragma once #include + #include #include -#include "Communication/CommunicationManager.h" -#include "Encode/LegacyEncodingManager.h" -#include "DeviceDriver/DeviceDriver.h" - #include "Bones.h" - +#include "Communication/CommunicationManager.h" #include "ControllerPose.h" #include "DeviceConfiguration.h" +#include "DeviceDriver/DeviceDriver.h" +#include "Encode/LegacyEncodingManager.h" +#include "ForceFeedback/FFBPipe.h" class KnuckleDeviceDriver : public IDeviceDriver { -public: - KnuckleDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, std::string serialNumber); + public: + KnuckleDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, std::string serialNumber); + + vr::EVRInitError Activate(uint32_t unObjectId); + void Deactivate(); - 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(); - void EnterStandby(); - void* GetComponent(const char* pchComponentNameAndVersion); - void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize); - vr::DriverPose_t GetPose(); - void RunFrame(); + std::string GetSerialNumber(); + bool IsActive(); - std::string GetSerialNumber(); - bool IsActive(); -private: - void StartDevice(); - bool IsRightHand() const; + private: + void StartDevice(); + bool IsRightHand() const; - bool m_hasActivated; - uint32_t m_driverId; + bool m_hasActivated; + uint32_t m_driverId; - vr::VRInputComponentHandle_t m_skeletalComponentHandle{}; - vr::VRInputComponentHandle_t m_inputComponentHandles[23]{}; + vr::VRInputComponentHandle_t m_skeletalComponentHandle{}; + vr::VRInputComponentHandle_t m_inputComponentHandles[23]{}; - vr::VRInputComponentHandle_t m_haptic{}; + vr::VRInputComponentHandle_t m_haptic{}; - vr::VRBoneTransform_t m_handTransforms[NUM_BONES]; + vr::VRBoneTransform_t m_handTransforms[NUM_BONES]; - VRDeviceConfiguration_t m_configuration; - std::unique_ptr m_communicationManager; - std::string m_serialNumber; + VRDeviceConfiguration_t m_configuration; + std::unique_ptr m_communicationManager; + std::string m_serialNumber; - std::unique_ptr m_controllerPose; + std::unique_ptr m_controllerPose; + std::unique_ptr m_ffbProvider; }; diff --git a/include/Encode/AlphaEncodingManager.h b/include/Encode/AlphaEncodingManager.h index 69277854..df2ace56 100644 --- a/include/Encode/AlphaEncodingManager.h +++ b/include/Encode/AlphaEncodingManager.h @@ -8,7 +8,9 @@ class AlphaEncodingManager : public IEncodingManager { //decode the given string into a VRCommData_t VRCommData_t Decode(std::string input); -private: + std::string Encode(const VRFFBData_t& input); + + private: std::string getArgumentSubstring(std::string str, char del); float m_maxAnalogValue; diff --git a/include/Encode/EncodingManager.h b/include/Encode/EncodingManager.h index 70e900db..8e7c6575 100644 --- a/include/Encode/EncodingManager.h +++ b/include/Encode/EncodingManager.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include "ForceFeedback/FFBPipe.h" struct VRCommData_t { VRCommData_t(std::array flexion, std::array splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool calibrate) : @@ -30,26 +31,28 @@ struct VRCommData_t { }; enum VRCommDataInputPosition { - FIN_PINKY, - FIN_RING, - FIN_MIDDLE, - FIN_INDEX, - FIN_THUMB, - JOY_X, - JOY_Y, - JOY_BTN, - BTN_TRG, - BTN_A, - BTN_B, - GES_GRAB, - GES_PINCH, - MAX, + FIN_PINKY, + FIN_RING, + FIN_MIDDLE, + FIN_INDEX, + FIN_THUMB, + JOY_X, + JOY_Y, + JOY_BTN, + BTN_TRG, + BTN_A, + BTN_B, + GES_GRAB, + GES_PINCH, + MAX, }; class IEncodingManager { -public: - virtual VRCommData_t Decode(std::string input) = 0; - virtual ~IEncodingManager() {}; -private: - float m_maxAnalogValue; + public: + virtual VRCommData_t Decode(std::string input) = 0; + virtual std::string Encode(const VRFFBData_t& data) = 0; + virtual ~IEncodingManager(){}; + + private: + float m_maxAnalogValue; }; \ No newline at end of file diff --git a/include/Encode/LegacyEncodingManager.h b/include/Encode/LegacyEncodingManager.h index 6ea31de1..39d88816 100644 --- a/include/Encode/LegacyEncodingManager.h +++ b/include/Encode/LegacyEncodingManager.h @@ -1,13 +1,16 @@ #pragma once #include +#include "ForceFeedback/FFBPipe.h" class LegacyEncodingManager : public IEncodingManager { -public: - LegacyEncodingManager(float maxAnalogValue) : m_maxAnalogValue(maxAnalogValue){}; - - //decode the given string into a VRCommData_t - VRCommData_t Decode(std::string input); -private: - float m_maxAnalogValue; + public: + LegacyEncodingManager(float maxAnalogValue) : m_maxAnalogValue(maxAnalogValue){}; + + VRCommData_t Decode(std::string input); + + std::string Encode(const VRFFBData_t& input); + + private: + float m_maxAnalogValue; }; \ No newline at end of file diff --git a/include/ForceFeedback/FFBPipe.h b/include/ForceFeedback/FFBPipe.h new file mode 100644 index 00000000..474fd35b --- /dev/null +++ b/include/ForceFeedback/FFBPipe.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include +#include +#include + +#include "openvr_driver.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; +}; +typedef struct { + OVERLAPPED oOverlap; + HANDLE hPipeInst; + VRFFBData_t chRequest; + DWORD cbRead; + DWORD cbToWrite; + std::function callback; +} PIPEINSTFFB, *LPPIPEINSTFFB; + +class FFBPipe { + public: + FFBPipe(); + bool Start(const std::function& callback, vr::ETrackedControllerRole handedness); + void Stop(); + + private: + void PipeListenerThread(const std::function& callback, vr::ETrackedControllerRole handedness); + void DisconnectAndClose(); + bool CreateAndConnectInstance(LPOVERLAPPED lpo, std::string& pipeName); + bool ConnectToNewClient(LPOVERLAPPED lpo); + HANDLE m_hPipe; + + std::thread m_pipeThread; + + std::atomic m_listenerActive; + std::atomic m_clientConnected; + + LPPIPEINSTFFB m_lpPipeInst; +}; \ No newline at end of file diff --git a/include/Pipe.h b/include/Pipe.h new file mode 100644 index 00000000..7d6f3004 --- /dev/null +++ b/include/Pipe.h @@ -0,0 +1,8 @@ +#pragma once +#include + +#include +#include +#include + +std::string GetLastErrorAsString(); \ No newline at end of file diff --git a/src/Bones.cpp b/src/Bones.cpp index 3de54d92..0fb5cafd 100644 --- a/src/Bones.cpp +++ b/src/Bones.cpp @@ -4,224 +4,215 @@ // these poses come from Valve's Index Controllers so share the same root bone to wrist // geometry assumptions. vr::VRBoneTransform_t rightOpenPose[NUM_BONES] = { -{ { 0.000000f, 0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ { 0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, 0.920279f, -0.379296f} }, -{ { 0.012083f, 0.028070f, 0.025050f, 1.000000f}, { 0.567418f, -0.464112f, 0.623374f, -0.272106f} }, -{ {-0.040406f, -0.000000f, 0.000000f, 1.000000f}, { 0.994838f, 0.082939f, 0.019454f, 0.055130f} }, -{ {-0.032517f, -0.000000f, -0.000000f, 1.000000f}, { 0.974793f, -0.003213f, 0.021867f, -0.222015f} }, -{ {-0.030464f, 0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ {-0.000632f, 0.026866f, 0.015002f, 1.000000f}, { 0.421979f, -0.644251f, 0.422133f, 0.478202f} }, -{ {-0.074204f, 0.005002f, -0.000234f, 1.000000f}, { 0.995332f, 0.007007f, -0.039124f, 0.087949f} }, -{ {-0.043930f, 0.000000f, 0.000000f, 1.000000f}, { 0.997891f, 0.045808f, 0.002142f, -0.045943f} }, -{ {-0.028695f, -0.000000f, -0.000000f, 1.000000f}, { 0.999649f, 0.001850f, -0.022782f, -0.013409f} }, -{ {-0.022821f, -0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, 0.000000f, -0.000000f} }, -{ {-0.002177f, 0.007120f, 0.016319f, 1.000000f}, { 0.541276f, -0.546723f, 0.460749f, 0.442520f} }, -{ {-0.070953f, -0.000779f, -0.000997f, 1.000000f}, { 0.980294f, -0.167261f, -0.078959f, 0.069368f} }, -{ {-0.043108f, -0.000000f, -0.000000f, 1.000000f}, { 0.997947f, 0.018493f, 0.013192f, 0.059886f} }, -{ {-0.033266f, -0.000000f, -0.000000f, 1.000000f}, { 0.997394f, -0.003328f, -0.028225f, -0.066315f} }, -{ {-0.025892f, 0.000000f, -0.000000f, 1.000000f}, { 0.999195f, -0.000000f, 0.000000f, 0.040126f} }, -{ {-0.000513f, -0.006545f, 0.016348f, 1.000000f}, { 0.550143f, -0.516692f, 0.429888f, 0.495548f} }, -{ {-0.065876f, -0.001786f, -0.000693f, 1.000000f}, { 0.990420f, -0.058696f, -0.101820f, 0.072495f} }, -{ {-0.040697f, -0.000000f, -0.000000f, 1.000000f}, { 0.999545f, -0.002240f, 0.000004f, 0.030081f} }, -{ {-0.028747f, 0.000000f, 0.000000f, 1.000000f}, { 0.999102f, -0.000721f, -0.012693f, 0.040420f} }, -{ {-0.022430f, 0.000000f, -0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ { 0.002478f, -0.018981f, 0.015214f, 1.000000f}, { 0.523940f, -0.526918f, 0.326740f, 0.584025f} }, -{ {-0.062878f, -0.002844f, -0.000332f, 1.000000f}, { 0.986609f, -0.059615f, -0.135163f, 0.069132f} }, -{ {-0.030220f, -0.000000f, -0.000000f, 1.000000f}, { 0.994317f, 0.001896f, -0.000132f, 0.106446f} }, -{ {-0.018187f, -0.000000f, -0.000000f, 1.000000f}, { 0.995931f, -0.002010f, -0.052079f, -0.073526f} }, -{ {-0.018018f, -0.000000f, 0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ { 0.006059f, 0.056285f, 0.060064f, 1.000000f}, { 0.737238f, 0.202745f, -0.594267f, -0.249441f} }, -{ { 0.040416f, -0.043018f, 0.019345f, 1.000000f}, {-0.290331f, 0.623527f, 0.663809f, 0.293734f} }, -{ { 0.039354f, -0.075674f, 0.047048f, 1.000000f}, {-0.187047f, 0.678062f, 0.659285f, 0.265683f} }, -{ { 0.038340f, -0.090987f, 0.082579f, 1.000000f}, {-0.183037f, 0.736793f, 0.634757f, 0.143936f} }, -{ { 0.031806f, -0.087214f, 0.121015f, 1.000000f}, {-0.003659f, 0.758407f, 0.639342f, 0.126678f} }, + {{0.000000f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, 0.920279f, -0.379296f}}, + {{0.012083f, 0.028070f, 0.025050f, 1.000000f}, {0.567418f, -0.464112f, 0.623374f, -0.272106f}}, + {{-0.040406f, -0.000000f, 0.000000f, 1.000000f}, {0.994838f, 0.082939f, 0.019454f, 0.055130f}}, + {{-0.032517f, -0.000000f, -0.000000f, 1.000000f}, {0.974793f, -0.003213f, 0.021867f, -0.222015f}}, + {{-0.030464f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{-0.000632f, 0.026866f, 0.015002f, 1.000000f}, {0.421979f, -0.644251f, 0.422133f, 0.478202f}}, + {{-0.074204f, 0.005002f, -0.000234f, 1.000000f}, {0.995332f, 0.007007f, -0.039124f, 0.087949f}}, + {{-0.043930f, 0.000000f, 0.000000f, 1.000000f}, {0.997891f, 0.045808f, 0.002142f, -0.045943f}}, + {{-0.028695f, -0.000000f, -0.000000f, 1.000000f}, {0.999649f, 0.001850f, -0.022782f, -0.013409f}}, + {{-0.022821f, -0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, 0.000000f, -0.000000f}}, + {{-0.002177f, 0.007120f, 0.016319f, 1.000000f}, {0.541276f, -0.546723f, 0.460749f, 0.442520f}}, + {{-0.070953f, -0.000779f, -0.000997f, 1.000000f}, {0.980294f, -0.167261f, -0.078959f, 0.069368f}}, + {{-0.043108f, -0.000000f, -0.000000f, 1.000000f}, {0.997947f, 0.018493f, 0.013192f, 0.059886f}}, + {{-0.033266f, -0.000000f, -0.000000f, 1.000000f}, {0.997394f, -0.003328f, -0.028225f, -0.066315f}}, + {{-0.025892f, 0.000000f, -0.000000f, 1.000000f}, {0.999195f, -0.000000f, 0.000000f, 0.040126f}}, + {{-0.000513f, -0.006545f, 0.016348f, 1.000000f}, {0.550143f, -0.516692f, 0.429888f, 0.495548f}}, + {{-0.065876f, -0.001786f, -0.000693f, 1.000000f}, {0.990420f, -0.058696f, -0.101820f, 0.072495f}}, + {{-0.040697f, -0.000000f, -0.000000f, 1.000000f}, {0.999545f, -0.002240f, 0.000004f, 0.030081f}}, + {{-0.028747f, 0.000000f, 0.000000f, 1.000000f}, {0.999102f, -0.000721f, -0.012693f, 0.040420f}}, + {{-0.022430f, 0.000000f, -0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{0.002478f, -0.018981f, 0.015214f, 1.000000f}, {0.523940f, -0.526918f, 0.326740f, 0.584025f}}, + {{-0.062878f, -0.002844f, -0.000332f, 1.000000f}, {0.986609f, -0.059615f, -0.135163f, 0.069132f}}, + {{-0.030220f, -0.000000f, -0.000000f, 1.000000f}, {0.994317f, 0.001896f, -0.000132f, 0.106446f}}, + {{-0.018187f, -0.000000f, -0.000000f, 1.000000f}, {0.995931f, -0.002010f, -0.052079f, -0.073526f}}, + {{-0.018018f, -0.000000f, 0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{0.006059f, 0.056285f, 0.060064f, 1.000000f}, {0.737238f, 0.202745f, -0.594267f, -0.249441f}}, + {{0.040416f, -0.043018f, 0.019345f, 1.000000f}, {-0.290331f, 0.623527f, 0.663809f, 0.293734f}}, + {{0.039354f, -0.075674f, 0.047048f, 1.000000f}, {-0.187047f, 0.678062f, 0.659285f, 0.265683f}}, + {{0.038340f, -0.090987f, 0.082579f, 1.000000f}, {-0.183037f, 0.736793f, 0.634757f, 0.143936f}}, + {{0.031806f, -0.087214f, 0.121015f, 1.000000f}, {-0.003659f, 0.758407f, 0.639342f, 0.126678f}}, }; -vr::VRBoneTransform_t rightFistPose[NUM_BONES] = -{ -{ { 0.000000f, 0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ { 0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, 0.920279f, -0.379296f} }, -{ { 0.016305f, 0.027529f, 0.017800f, 1.000000f}, { 0.483332f, -0.225703f, 0.836342f, -0.126413f} }, -{ {-0.040406f, -0.000000f, 0.000000f, 1.000000f}, { 0.894335f, -0.013302f, -0.082902f, 0.439448f} }, -{ {-0.032517f, -0.000000f, -0.000000f, 1.000000f}, { 0.842428f, 0.000655f, 0.001244f, 0.538807f} }, -{ {-0.030464f, 0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ {-0.003802f, 0.021514f, 0.012803f, 1.000000f}, { 0.395174f, -0.617314f, 0.449185f, 0.510874f} }, -{ {-0.074204f, 0.005002f, -0.000234f, 1.000000f}, { 0.737291f, -0.032006f, -0.115013f, 0.664944f} }, -{ {-0.043287f, 0.000000f, 0.000000f, 1.000000f}, { 0.611381f, 0.003287f, 0.003823f, 0.791321f} }, -{ {-0.028275f, -0.000000f, -0.000000f, 1.000000f}, { 0.745388f, -0.000684f, -0.000945f, 0.666629f} }, -{ {-0.022821f, -0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, 0.000000f, -0.000000f} }, -{ {-0.005787f, 0.006806f, 0.016534f, 1.000000f}, { 0.522315f, -0.514203f, 0.483700f, 0.478348f} }, -{ {-0.070953f, -0.000779f, -0.000997f, 1.000000f}, { 0.723653f, -0.097901f, 0.048546f, 0.681458f} }, -{ {-0.043108f, -0.000000f, -0.000000f, 1.000000f}, { 0.637464f, -0.002366f, -0.002831f, 0.770472f} }, -{ {-0.033266f, -0.000000f, -0.000000f, 1.000000f}, { 0.658008f, 0.002610f, 0.003196f, 0.753000f} }, -{ {-0.025892f, 0.000000f, -0.000000f, 1.000000f}, { 0.999195f, -0.000000f, 0.000000f, 0.040126f} }, -{ {-0.004123f, -0.006858f, 0.016563f, 1.000000f}, { 0.523374f, -0.489609f, 0.463997f, 0.520644f} }, -{ {-0.065876f, -0.001786f, -0.000693f, 1.000000f}, { 0.759970f, -0.055609f, 0.011571f, 0.647471f} }, -{ {-0.040331f, -0.000000f, -0.000000f, 1.000000f}, { 0.664315f, 0.001595f, 0.001967f, 0.747449f} }, -{ {-0.028489f, 0.000000f, 0.000000f, 1.000000f}, { 0.626957f, -0.002784f, -0.003234f, 0.779042f} }, -{ {-0.022430f, 0.000000f, -0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ {-0.001131f, -0.019295f, 0.015429f, 1.000000f}, { 0.477833f, -0.479766f, 0.379935f, 0.630198f} }, -{ {-0.062878f, -0.002844f, -0.000332f, 1.000000f}, { 0.827001f, 0.034282f, 0.003440f, 0.561144f} }, -{ {-0.029874f, -0.000000f, -0.000000f, 1.000000f}, { 0.702185f, -0.006716f, -0.009289f, 0.711903f} }, -{ {-0.017979f, -0.000000f, -0.000000f, 1.000000f}, { 0.676853f, 0.007956f, 0.009917f, 0.736009f} }, -{ {-0.018018f, -0.000000f, 0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ {-0.019716f, 0.002802f, 0.093937f, 1.000000f}, { 0.377286f, -0.540831f, -0.150446f, 0.736562f} }, -{ {-0.000171f, 0.016473f, 0.096515f, 1.000000f}, {-0.006456f, 0.022747f, 0.932927f, 0.359287f} }, -{ {-0.000448f, 0.001536f, 0.116543f, 1.000000f}, {-0.039357f, 0.105143f, 0.928833f, 0.353079f} }, -{ {-0.003949f, -0.014869f, 0.130608f, 1.000000f}, {-0.055071f, 0.068695f, 0.944016f, 0.317933f} }, -{ {-0.003263f, -0.034685f, 0.139926f, 1.000000f}, { 0.019690f, -0.100741f, 0.957331f, 0.270149f} }, +vr::VRBoneTransform_t rightFistPose[NUM_BONES] = { + {{0.000000f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, 0.920279f, -0.379296f}}, + {{0.016305f, 0.027529f, 0.017800f, 1.000000f}, {0.483332f, -0.225703f, 0.836342f, -0.126413f}}, + {{-0.040406f, -0.000000f, 0.000000f, 1.000000f}, {0.894335f, -0.013302f, -0.082902f, 0.439448f}}, + {{-0.032517f, -0.000000f, -0.000000f, 1.000000f}, {0.842428f, 0.000655f, 0.001244f, 0.538807f}}, + {{-0.030464f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{-0.003802f, 0.021514f, 0.012803f, 1.000000f}, {0.395174f, -0.617314f, 0.449185f, 0.510874f}}, + {{-0.074204f, 0.005002f, -0.000234f, 1.000000f}, {0.737291f, -0.032006f, -0.115013f, 0.664944f}}, + {{-0.043287f, 0.000000f, 0.000000f, 1.000000f}, {0.611381f, 0.003287f, 0.003823f, 0.791321f}}, + {{-0.028275f, -0.000000f, -0.000000f, 1.000000f}, {0.745388f, -0.000684f, -0.000945f, 0.666629f}}, + {{-0.022821f, -0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, 0.000000f, -0.000000f}}, + {{-0.005787f, 0.006806f, 0.016534f, 1.000000f}, {0.522315f, -0.514203f, 0.483700f, 0.478348f}}, + {{-0.070953f, -0.000779f, -0.000997f, 1.000000f}, {0.723653f, -0.097901f, 0.048546f, 0.681458f}}, + {{-0.043108f, -0.000000f, -0.000000f, 1.000000f}, {0.637464f, -0.002366f, -0.002831f, 0.770472f}}, + {{-0.033266f, -0.000000f, -0.000000f, 1.000000f}, {0.658008f, 0.002610f, 0.003196f, 0.753000f}}, + {{-0.025892f, 0.000000f, -0.000000f, 1.000000f}, {0.999195f, -0.000000f, 0.000000f, 0.040126f}}, + {{-0.004123f, -0.006858f, 0.016563f, 1.000000f}, {0.523374f, -0.489609f, 0.463997f, 0.520644f}}, + {{-0.065876f, -0.001786f, -0.000693f, 1.000000f}, {0.759970f, -0.055609f, 0.011571f, 0.647471f}}, + {{-0.040331f, -0.000000f, -0.000000f, 1.000000f}, {0.664315f, 0.001595f, 0.001967f, 0.747449f}}, + {{-0.028489f, 0.000000f, 0.000000f, 1.000000f}, {0.626957f, -0.002784f, -0.003234f, 0.779042f}}, + {{-0.022430f, 0.000000f, -0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{-0.001131f, -0.019295f, 0.015429f, 1.000000f}, {0.477833f, -0.479766f, 0.379935f, 0.630198f}}, + {{-0.062878f, -0.002844f, -0.000332f, 1.000000f}, {0.827001f, 0.034282f, 0.003440f, 0.561144f}}, + {{-0.029874f, -0.000000f, -0.000000f, 1.000000f}, {0.702185f, -0.006716f, -0.009289f, 0.711903f}}, + {{-0.017979f, -0.000000f, -0.000000f, 1.000000f}, {0.676853f, 0.007956f, 0.009917f, 0.736009f}}, + {{-0.018018f, -0.000000f, 0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{-0.019716f, 0.002802f, 0.093937f, 1.000000f}, {0.377286f, -0.540831f, -0.150446f, 0.736562f}}, + {{-0.000171f, 0.016473f, 0.096515f, 1.000000f}, {-0.006456f, 0.022747f, 0.932927f, 0.359287f}}, + {{-0.000448f, 0.001536f, 0.116543f, 1.000000f}, {-0.039357f, 0.105143f, 0.928833f, 0.353079f}}, + {{-0.003949f, -0.014869f, 0.130608f, 1.000000f}, {-0.055071f, 0.068695f, 0.944016f, 0.317933f}}, + {{-0.003263f, -0.034685f, 0.139926f, 1.000000f}, {0.019690f, -0.100741f, 0.957331f, 0.270149f}}, }; vr::VRBoneTransform_t leftOpenPose[NUM_BONES] = { -{ { 0.000000f, 0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ {-0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, -0.920279f, 0.379296f} }, -{ {-0.012083f, 0.028070f, 0.025050f, 1.000000f}, { 0.464112f, 0.567418f, 0.272106f, 0.623374f} }, -{ { 0.040406f, 0.000000f, -0.000000f, 1.000000f}, { 0.994838f, 0.082939f, 0.019454f, 0.055130f} }, -{ { 0.032517f, 0.000000f, 0.000000f, 1.000000f}, { 0.974793f, -0.003213f, 0.021867f, -0.222015f} }, -{ { 0.030464f, -0.000000f, -0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ { 0.000632f, 0.026866f, 0.015002f, 1.000000f}, { 0.644251f, 0.421979f, -0.478202f, 0.422133f} }, -{ { 0.074204f, -0.005002f, 0.000234f, 1.000000f}, { 0.995332f, 0.007007f, -0.039124f, 0.087949f} }, -{ { 0.043930f, -0.000000f, -0.000000f, 1.000000f}, { 0.997891f, 0.045808f, 0.002142f, -0.045943f} }, -{ { 0.028695f, 0.000000f, 0.000000f, 1.000000f}, { 0.999649f, 0.001850f, -0.022782f, -0.013409f} }, -{ { 0.022821f, 0.000000f, -0.000000f, 1.000000f}, { 1.000000f, -0.000000f, 0.000000f, -0.000000f} }, -{ { 0.002177f, 0.007120f, 0.016319f, 1.000000f}, { 0.546723f, 0.541276f, -0.442520f, 0.460749f} }, -{ { 0.070953f, 0.000779f, 0.000997f, 1.000000f}, { 0.980294f, -0.167261f, -0.078959f, 0.069368f} }, -{ { 0.043108f, 0.000000f, 0.000000f, 1.000000f}, { 0.997947f, 0.018493f, 0.013192f, 0.059886f} }, -{ { 0.033266f, 0.000000f, 0.000000f, 1.000000f}, { 0.997394f, -0.003328f, -0.028225f, -0.066315f} }, -{ { 0.025892f, -0.000000f, 0.000000f, 1.000000f}, { 0.999195f, -0.000000f, 0.000000f, 0.040126f} }, -{ { 0.000513f, -0.006545f, 0.016348f, 1.000000f}, { 0.516692f, 0.550143f, -0.495548f, 0.429888f} }, -{ { 0.065876f, 0.001786f, 0.000693f, 1.000000f}, { 0.990420f, -0.058696f, -0.101820f, 0.072495f} }, -{ { 0.040697f, 0.000000f, 0.000000f, 1.000000f}, { 0.999545f, -0.002240f, 0.000004f, 0.030081f} }, -{ { 0.028747f, -0.000000f, -0.000000f, 1.000000f}, { 0.999102f, -0.000721f, -0.012693f, 0.040420f} }, -{ { 0.022430f, -0.000000f, 0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ {-0.002478f, -0.018981f, 0.015214f, 1.000000f}, { 0.526918f, 0.523940f, -0.584025f, 0.326740f} }, -{ { 0.062878f, 0.002844f, 0.000332f, 1.000000f}, { 0.986609f, -0.059615f, -0.135163f, 0.069132f} }, -{ { 0.030220f, 0.000000f, 0.000000f, 1.000000f}, { 0.994317f, 0.001896f, -0.000132f, 0.106446f} }, -{ { 0.018187f, 0.000000f, 0.000000f, 1.000000f}, { 0.995931f, -0.002010f, -0.052079f, -0.073526f} }, -{ { 0.018018f, 0.000000f, -0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ {-0.006059f, 0.056285f, 0.060064f, 1.000000f}, { 0.737238f, 0.202745f, 0.594267f, 0.249441f} }, -{ {-0.040416f, -0.043018f, 0.019345f, 1.000000f}, {-0.290331f, 0.623527f, -0.663809f, -0.293734f} }, -{ {-0.039354f, -0.075674f, 0.047048f, 1.000000f}, {-0.187047f, 0.678062f, -0.659285f, -0.265683f} }, -{ {-0.038340f, -0.090987f, 0.082579f, 1.000000f}, {-0.183037f, 0.736793f, -0.634757f, -0.143936f} }, -{ {-0.031806f, -0.087214f, 0.121015f, 1.000000f}, {-0.003659f, 0.758407f, -0.639342f, -0.126678f} }, + {{0.000000f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{-0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, -0.920279f, 0.379296f}}, + {{-0.012083f, 0.028070f, 0.025050f, 1.000000f}, {0.464112f, 0.567418f, 0.272106f, 0.623374f}}, + {{0.040406f, 0.000000f, -0.000000f, 1.000000f}, {0.994838f, 0.082939f, 0.019454f, 0.055130f}}, + {{0.032517f, 0.000000f, 0.000000f, 1.000000f}, {0.974793f, -0.003213f, 0.021867f, -0.222015f}}, + {{0.030464f, -0.000000f, -0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{0.000632f, 0.026866f, 0.015002f, 1.000000f}, {0.644251f, 0.421979f, -0.478202f, 0.422133f}}, + {{0.074204f, -0.005002f, 0.000234f, 1.000000f}, {0.995332f, 0.007007f, -0.039124f, 0.087949f}}, + {{0.043930f, -0.000000f, -0.000000f, 1.000000f}, {0.997891f, 0.045808f, 0.002142f, -0.045943f}}, + {{0.028695f, 0.000000f, 0.000000f, 1.000000f}, {0.999649f, 0.001850f, -0.022782f, -0.013409f}}, + {{0.022821f, 0.000000f, -0.000000f, 1.000000f}, {1.000000f, -0.000000f, 0.000000f, -0.000000f}}, + {{0.002177f, 0.007120f, 0.016319f, 1.000000f}, {0.546723f, 0.541276f, -0.442520f, 0.460749f}}, + {{0.070953f, 0.000779f, 0.000997f, 1.000000f}, {0.980294f, -0.167261f, -0.078959f, 0.069368f}}, + {{0.043108f, 0.000000f, 0.000000f, 1.000000f}, {0.997947f, 0.018493f, 0.013192f, 0.059886f}}, + {{0.033266f, 0.000000f, 0.000000f, 1.000000f}, {0.997394f, -0.003328f, -0.028225f, -0.066315f}}, + {{0.025892f, -0.000000f, 0.000000f, 1.000000f}, {0.999195f, -0.000000f, 0.000000f, 0.040126f}}, + {{0.000513f, -0.006545f, 0.016348f, 1.000000f}, {0.516692f, 0.550143f, -0.495548f, 0.429888f}}, + {{0.065876f, 0.001786f, 0.000693f, 1.000000f}, {0.990420f, -0.058696f, -0.101820f, 0.072495f}}, + {{0.040697f, 0.000000f, 0.000000f, 1.000000f}, {0.999545f, -0.002240f, 0.000004f, 0.030081f}}, + {{0.028747f, -0.000000f, -0.000000f, 1.000000f}, {0.999102f, -0.000721f, -0.012693f, 0.040420f}}, + {{0.022430f, -0.000000f, 0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{-0.002478f, -0.018981f, 0.015214f, 1.000000f}, {0.526918f, 0.523940f, -0.584025f, 0.326740f}}, + {{0.062878f, 0.002844f, 0.000332f, 1.000000f}, {0.986609f, -0.059615f, -0.135163f, 0.069132f}}, + {{0.030220f, 0.000000f, 0.000000f, 1.000000f}, {0.994317f, 0.001896f, -0.000132f, 0.106446f}}, + {{0.018187f, 0.000000f, 0.000000f, 1.000000f}, {0.995931f, -0.002010f, -0.052079f, -0.073526f}}, + {{0.018018f, 0.000000f, -0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{-0.006059f, 0.056285f, 0.060064f, 1.000000f}, {0.737238f, 0.202745f, 0.594267f, 0.249441f}}, + {{-0.040416f, -0.043018f, 0.019345f, 1.000000f}, {-0.290331f, 0.623527f, -0.663809f, -0.293734f}}, + {{-0.039354f, -0.075674f, 0.047048f, 1.000000f}, {-0.187047f, 0.678062f, -0.659285f, -0.265683f}}, + {{-0.038340f, -0.090987f, 0.082579f, 1.000000f}, {-0.183037f, 0.736793f, -0.634757f, -0.143936f}}, + {{-0.031806f, -0.087214f, 0.121015f, 1.000000f}, {-0.003659f, 0.758407f, -0.639342f, -0.126678f}}, }; vr::VRBoneTransform_t leftFistPose[NUM_BONES] = { -{ { 0.000000f, 0.000000f, 0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ {-0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, -0.920279f, 0.379296f} }, -{ {-0.016305f, 0.027529f, 0.017800f, 1.000000f}, { 0.225703f, 0.483332f, 0.126413f, 0.836342f} }, -{ { 0.040406f, 0.000000f, -0.000000f, 1.000000f}, { 0.894335f, -0.013302f, -0.082902f, 0.439448f} }, -{ { 0.032517f, 0.000000f, 0.000000f, 1.000000f}, { 0.842428f, 0.000655f, 0.001244f, 0.538807f} }, -{ { 0.030464f, -0.000000f, -0.000000f, 1.000000f}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f} }, -{ { 0.003802f, 0.021514f, 0.012803f, 1.000000f}, { 0.617314f, 0.395175f, -0.510874f, 0.449185f} }, -{ { 0.074204f, -0.005002f, 0.000234f, 1.000000f}, { 0.737291f, -0.032006f, -0.115013f, 0.664944f} }, -{ { 0.043287f, -0.000000f, -0.000000f, 1.000000f}, { 0.611381f, 0.003287f, 0.003823f, 0.791321f} }, -{ { 0.028275f, 0.000000f, 0.000000f, 1.000000f}, { 0.745388f, -0.000684f, -0.000945f, 0.666629f} }, -{ { 0.022821f, 0.000000f, -0.000000f, 1.000000f}, { 1.000000f, -0.000000f, 0.000000f, -0.000000f} }, -{ { 0.005787f, 0.006806f, 0.016534f, 1.000000f}, { 0.514203f, 0.522315f, -0.478348f, 0.483700f} }, -{ { 0.070953f, 0.000779f, 0.000997f, 1.000000f}, { 0.723653f, -0.097901f, 0.048546f, 0.681458f} }, -{ { 0.043108f, 0.000000f, 0.000000f, 1.000000f}, { 0.637464f, -0.002366f, -0.002831f, 0.770472f} }, -{ { 0.033266f, 0.000000f, 0.000000f, 1.000000f}, { 0.658008f, 0.002610f, 0.003196f, 0.753000f} }, -{ { 0.025892f, -0.000000f, 0.000000f, 1.000000f}, { 0.999195f, -0.000000f, 0.000000f, 0.040126f} }, -{ { 0.004123f, -0.006858f, 0.016563f, 1.000000f}, { 0.489609f, 0.523374f, -0.520644f, 0.463997f} }, -{ { 0.065876f, 0.001786f, 0.000693f, 1.000000f}, { 0.759970f, -0.055609f, 0.011571f, 0.647471f} }, -{ { 0.040331f, 0.000000f, 0.000000f, 1.000000f}, { 0.664315f, 0.001595f, 0.001967f, 0.747449f} }, -{ { 0.028489f, -0.000000f, -0.000000f, 1.000000f}, { 0.626957f, -0.002784f, -0.003234f, 0.779042f} }, -{ { 0.022430f, -0.000000f, 0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ { 0.001131f, -0.019295f, 0.015429f, 1.000000f}, { 0.479766f, 0.477833f, -0.630198f, 0.379934f} }, -{ { 0.062878f, 0.002844f, 0.000332f, 1.000000f}, { 0.827001f, 0.034282f, 0.003440f, 0.561144f} }, -{ { 0.029874f, 0.000000f, 0.000000f, 1.000000f}, { 0.702185f, -0.006716f, -0.009289f, 0.711903f} }, -{ { 0.017979f, 0.000000f, 0.000000f, 1.000000f}, { 0.676853f, 0.007956f, 0.009917f, 0.736009f} }, -{ { 0.018018f, 0.000000f, -0.000000f, 1.000000f}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f} }, -{ { 0.019716f, 0.002802f, 0.093937f, 1.000000f}, { 0.377286f, -0.540831f, 0.150446f, -0.736562f} }, -{ { 0.000171f, 0.016473f, 0.096515f, 1.000000f}, {-0.006456f, 0.022747f, -0.932927f, -0.359287f} }, -{ { 0.000448f, 0.001536f, 0.116543f, 1.000000f}, {-0.039357f, 0.105143f, -0.928833f, -0.353079f} }, -{ { 0.003949f, -0.014869f, 0.130608f, 1.000000f}, {-0.055071f, 0.068695f, -0.944016f, -0.317933f} }, -{ { 0.003263f, -0.034685f, 0.139926f, 1.000000f}, { 0.019690f, -0.100741f, -0.957331f, -0.270149f} }, + {{0.000000f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{-0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, -0.920279f, 0.379296f}}, + {{-0.016305f, 0.027529f, 0.017800f, 1.000000f}, {0.225703f, 0.483332f, 0.126413f, 0.836342f}}, + {{0.040406f, 0.000000f, -0.000000f, 1.000000f}, {0.894335f, -0.013302f, -0.082902f, 0.439448f}}, + {{0.032517f, 0.000000f, 0.000000f, 1.000000f}, {0.842428f, 0.000655f, 0.001244f, 0.538807f}}, + {{0.030464f, -0.000000f, -0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}}, + {{0.003802f, 0.021514f, 0.012803f, 1.000000f}, {0.617314f, 0.395175f, -0.510874f, 0.449185f}}, + {{0.074204f, -0.005002f, 0.000234f, 1.000000f}, {0.737291f, -0.032006f, -0.115013f, 0.664944f}}, + {{0.043287f, -0.000000f, -0.000000f, 1.000000f}, {0.611381f, 0.003287f, 0.003823f, 0.791321f}}, + {{0.028275f, 0.000000f, 0.000000f, 1.000000f}, {0.745388f, -0.000684f, -0.000945f, 0.666629f}}, + {{0.022821f, 0.000000f, -0.000000f, 1.000000f}, {1.000000f, -0.000000f, 0.000000f, -0.000000f}}, + {{0.005787f, 0.006806f, 0.016534f, 1.000000f}, {0.514203f, 0.522315f, -0.478348f, 0.483700f}}, + {{0.070953f, 0.000779f, 0.000997f, 1.000000f}, {0.723653f, -0.097901f, 0.048546f, 0.681458f}}, + {{0.043108f, 0.000000f, 0.000000f, 1.000000f}, {0.637464f, -0.002366f, -0.002831f, 0.770472f}}, + {{0.033266f, 0.000000f, 0.000000f, 1.000000f}, {0.658008f, 0.002610f, 0.003196f, 0.753000f}}, + {{0.025892f, -0.000000f, 0.000000f, 1.000000f}, {0.999195f, -0.000000f, 0.000000f, 0.040126f}}, + {{0.004123f, -0.006858f, 0.016563f, 1.000000f}, {0.489609f, 0.523374f, -0.520644f, 0.463997f}}, + {{0.065876f, 0.001786f, 0.000693f, 1.000000f}, {0.759970f, -0.055609f, 0.011571f, 0.647471f}}, + {{0.040331f, 0.000000f, 0.000000f, 1.000000f}, {0.664315f, 0.001595f, 0.001967f, 0.747449f}}, + {{0.028489f, -0.000000f, -0.000000f, 1.000000f}, {0.626957f, -0.002784f, -0.003234f, 0.779042f}}, + {{0.022430f, -0.000000f, 0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{0.001131f, -0.019295f, 0.015429f, 1.000000f}, {0.479766f, 0.477833f, -0.630198f, 0.379934f}}, + {{0.062878f, 0.002844f, 0.000332f, 1.000000f}, {0.827001f, 0.034282f, 0.003440f, 0.561144f}}, + {{0.029874f, 0.000000f, 0.000000f, 1.000000f}, {0.702185f, -0.006716f, -0.009289f, 0.711903f}}, + {{0.017979f, 0.000000f, 0.000000f, 1.000000f}, {0.676853f, 0.007956f, 0.009917f, 0.736009f}}, + {{0.018018f, 0.000000f, -0.000000f, 1.000000f}, {1.000000f, 0.000000f, 0.000000f, 0.000000f}}, + {{0.019716f, 0.002802f, 0.093937f, 1.000000f}, {0.377286f, -0.540831f, 0.150446f, -0.736562f}}, + {{0.000171f, 0.016473f, 0.096515f, 1.000000f}, {-0.006456f, 0.022747f, -0.932927f, -0.359287f}}, + {{0.000448f, 0.001536f, 0.116543f, 1.000000f}, {-0.039357f, 0.105143f, -0.928833f, -0.353079f}}, + {{0.003949f, -0.014869f, 0.130608f, 1.000000f}, {-0.055071f, 0.068695f, -0.944016f, -0.317933f}}, + {{0.003263f, -0.034685f, 0.139926f, 1.000000f}, {0.019690f, -0.100741f, -0.957331f, -0.270149f}}, }; vr::HmdQuaternionf_t CalculateOrientation(const float transform, const int boneIndex, const vr::VRBoneTransform_t* openPose, const vr::VRBoneTransform_t* fistPose) { + const vr::HmdQuaternionf_t openPoseOrientation = openPose[boneIndex].orientation; + const vr::HmdQuaternionf_t fistPoseOrientation = fistPose[boneIndex].orientation; - const vr::HmdQuaternionf_t openPoseOrientation = openPose[boneIndex].orientation; - const vr::HmdQuaternionf_t fistPoseOrientation = fistPose[boneIndex].orientation; + vr::HmdQuaternionf_t result; + result.w = Lerp(openPoseOrientation.w, fistPoseOrientation.w, transform); + result.x = Lerp(openPoseOrientation.x, fistPoseOrientation.x, transform); + result.y = Lerp(openPoseOrientation.y, fistPoseOrientation.y, transform); + result.z = Lerp(openPoseOrientation.z, fistPoseOrientation.z, transform); - vr::HmdQuaternionf_t result; - result.w = Lerp(openPoseOrientation.w, fistPoseOrientation.w, transform); - result.x = Lerp(openPoseOrientation.x, fistPoseOrientation.x, transform); - result.y = Lerp(openPoseOrientation.y, fistPoseOrientation.y, transform); - result.z = Lerp(openPoseOrientation.z, fistPoseOrientation.z, transform); - - return result; + return result; } vr::HmdVector4_t CalculatePosition(const float transform, const int boneIndex, const vr::VRBoneTransform_t* openPose, const vr::VRBoneTransform_t* fistPose) { + const vr::HmdVector4_t openPosePosition = openPose[boneIndex].position; + const vr::HmdVector4_t fistPosePosition = fistPose[boneIndex].position; - const vr::HmdVector4_t openPosePosition = openPose[boneIndex].position; - const vr::HmdVector4_t fistPosePosition = fistPose[boneIndex].position; - - vr::HmdVector4_t result; - result.v[0] = Lerp(openPosePosition.v[0], fistPosePosition.v[0], transform); - result.v[1] = Lerp(openPosePosition.v[1], fistPosePosition.v[1], transform); - result.v[2] = Lerp(openPosePosition.v[2], fistPosePosition.v[2], transform); - result.v[3] = Lerp(openPosePosition.v[3], fistPosePosition.v[3], transform); + vr::HmdVector4_t result; + result.v[0] = Lerp(openPosePosition.v[0], fistPosePosition.v[0], transform); + result.v[1] = Lerp(openPosePosition.v[1], fistPosePosition.v[1], transform); + result.v[2] = Lerp(openPosePosition.v[2], fistPosePosition.v[2], transform); + result.v[3] = Lerp(openPosePosition.v[3], fistPosePosition.v[3], transform); - return result; + return result; } -//Transform should be between 0-1 +// Transform should be between 0-1 void ComputeBoneFlexion(vr::VRBoneTransform_t* bone_transform, float transform, int index, const bool isRightHand) { + vr::VRBoneTransform_t* fist_pose = isRightHand ? rightFistPose : leftFistPose; + vr::VRBoneTransform_t* open_pose = isRightHand ? rightOpenPose : leftOpenPose; - vr::VRBoneTransform_t* fist_pose = isRightHand ? rightFistPose : leftFistPose; - vr::VRBoneTransform_t* open_pose = isRightHand ? rightOpenPose : leftOpenPose; - - - bone_transform->orientation = CalculateOrientation(transform, index, open_pose, fist_pose); - bone_transform->position = CalculatePosition(transform, index, open_pose, fist_pose); + bone_transform->orientation = CalculateOrientation(transform, index, open_pose, fist_pose); + bone_transform->position = CalculatePosition(transform, index, open_pose, fist_pose); } - -float Lerp(const float a, const float b, const float f) { - return a + f * (b - a); -} +float Lerp(const float a, const float b, const float f) { return a + f * (b - a); } int FingerFromBone(vr::BoneIndex_t bone) { - switch (bone) { - case eBone_Thumb0: - case eBone_Thumb1: - case eBone_Thumb2: - case eBone_Thumb3: - case eBone_Aux_Thumb: - return 0; - case eBone_IndexFinger0: - case eBone_IndexFinger1: - case eBone_IndexFinger2: - case eBone_IndexFinger3: - case eBone_IndexFinger4: - case eBone_Aux_IndexFinger: - return 1; - case eBone_MiddleFinger0: - case eBone_MiddleFinger1: - case eBone_MiddleFinger2: - case eBone_MiddleFinger3: - case eBone_MiddleFinger4: - case eBone_Aux_MiddleFinger: - return 2; - case eBone_RingFinger0: - case eBone_RingFinger1: - case eBone_RingFinger2: - case eBone_RingFinger3: - case eBone_RingFinger4: - case eBone_Aux_RingFinger: - return 3; - case eBone_PinkyFinger0: - case eBone_PinkyFinger1: - case eBone_PinkyFinger2: - case eBone_PinkyFinger3: - case eBone_PinkyFinger4: - case eBone_Aux_PinkyFinger: - return 4; - - default: - return -1; - } - + switch (bone) { + case eBone_Thumb0: + case eBone_Thumb1: + case eBone_Thumb2: + case eBone_Thumb3: + case eBone_Aux_Thumb: + return 0; + case eBone_IndexFinger0: + case eBone_IndexFinger1: + case eBone_IndexFinger2: + case eBone_IndexFinger3: + case eBone_IndexFinger4: + case eBone_Aux_IndexFinger: + return 1; + case eBone_MiddleFinger0: + case eBone_MiddleFinger1: + case eBone_MiddleFinger2: + case eBone_MiddleFinger3: + case eBone_MiddleFinger4: + case eBone_Aux_MiddleFinger: + return 2; + case eBone_RingFinger0: + case eBone_RingFinger1: + case eBone_RingFinger2: + case eBone_RingFinger3: + case eBone_RingFinger4: + case eBone_Aux_RingFinger: + return 3; + case eBone_PinkyFinger0: + case eBone_PinkyFinger1: + case eBone_PinkyFinger2: + case eBone_PinkyFinger3: + case eBone_PinkyFinger4: + case eBone_Aux_PinkyFinger: + return 4; + + default: + return -1; + } } \ No newline at end of file diff --git a/src/Communication/BTSerialCommunicationManager.cpp b/src/Communication/BTSerialCommunicationManager.cpp index 4b6a5d44..08999b81 100644 --- a/src/Communication/BTSerialCommunicationManager.cpp +++ b/src/Communication/BTSerialCommunicationManager.cpp @@ -1,222 +1,196 @@ #include -//Adapted from Finally Functional's SerialBT implementation +// Adapted from Finally Functional's SerialBT implementation -BTSerialCommunicationManager::BTSerialCommunicationManager(const VRBTSerialConfiguration_t& configuration, std::unique_ptr encodingManager) - : m_btSerialConfiguration(configuration), - m_encodingManager(std::move(encodingManager)), - m_isConnected(false) -{ - //convert the bluetooth device name from settings into wide - //const char* name = configuration.name.c_str(); - //size_t newsize = strlen(name) + 1; - //m_wcDeviceName = new WCHAR[newsize]; - //size_t convertedChars = 0; - //mbstowcs_s(&convertedChars, m_wcDeviceName, newsize, name, _TRUNCATE); - - //std::wstring thiswstring = std::wstring(configuration.name.begin(), configuration.name.end()); - - //m_wcDeviceName = (WCHAR*)(thiswstring.c_str()); - - -}; +BTSerialCommunicationManager::BTSerialCommunicationManager(const VRBTSerialConfiguration_t& configuration, std::unique_ptr encodingManager) + : m_btSerialConfiguration(configuration), m_encodingManager(std::move(encodingManager)), m_isConnected(false){}; void BTSerialCommunicationManager::Connect() { - DriverLog("Trying to connect to bluetooth"); - - //We're not yet connected - m_isConnected = false; - - //Try to connect - if (!getPairedEsp32BtAddress()) //find an ESP32 paired with this machine - { - DriverLog("Error getting Bluetooth address"); - return; - } - if (!startupWindowsSocket()) //initialize windows sockets - { - DriverLog("Error Initializing windows sockets"); - return; - } - if (!connectToEsp32()) //initialize BT windows socket for connecting to ESP32 - { - DriverLog("Error connecting to Bluetooth device"); - return; - } - else { - //If everything went fine we're connected - m_isConnected = true; - DriverLog("Connected to bluetooth!"); - } + DriverLog("Trying to connect to bluetooth"); + + // We're not yet connected + m_isConnected = false; + + // Try to connect + if (!getPairedEsp32BtAddress()) // find an ESP32 paired with this machine + { + DriverLog("Error getting Bluetooth address"); + return; + } + if (!startupWindowsSocket()) // initialize windows sockets + { + DriverLog("Error Initializing windows sockets"); + return; + } + if (!connectToEsp32()) // initialize BT windows socket for connecting to ESP32 + { + DriverLog("Error connecting to Bluetooth device"); + return; + } else { + // If everything went fine we're connected + m_isConnected = true; + DriverLog("Connected to bluetooth!"); + } } void BTSerialCommunicationManager::BeginListener(const std::function& callback) { - DriverLog("Begun listener"); - m_threadActive = true; - m_serialThread = std::thread(&BTSerialCommunicationManager::ListenerThread, this, callback); + DriverLog("Begun listener"); + m_threadActive = true; + m_serialThread = std::thread(&BTSerialCommunicationManager::ListenerThread, this, callback); } void BTSerialCommunicationManager::ListenerThread(const std::function& callback) { - //DebugDriverLog("In listener thread"); - std::this_thread::sleep_for(std::chrono::milliseconds(ARDUINO_WAIT_TIME)); - - while (m_threadActive) { - std::string receivedString; - bool readSuccessful = ReceiveNextPacket(receivedString); - - if (readSuccessful) { - try { - VRCommData_t commData = m_encodingManager->Decode(receivedString); - callback(commData); - } - catch (const std::invalid_argument& ia) { - DriverLog("Received error from encoding manager. Skipping..."); - } - } - else { - DriverLog("Detected that arduino has disconnected! Stopping listener..."); - //We should probably do more logic for trying to reconnect to the arduino - //For now, it should be obvious to people that the arduinos have disconnected - m_threadActive = false; - } - - } + // DebugDriverLog("In listener thread"); + std::this_thread::sleep_for(std::chrono::milliseconds(ARDUINO_WAIT_TIME)); + + while (m_threadActive) { + std::string receivedString; + bool readSuccessful = ReceiveNextPacket(receivedString); + if (readSuccessful) { + try { + VRCommData_t commData = m_encodingManager->Decode(receivedString); + callback(commData); + sendMessageToEsp32(); + } catch (const std::invalid_argument& ia) { + DriverLog("Received error from encoding manager. Skipping..."); + } + } else { + DriverLog("Detected that arduino has disconnected! Stopping listener..."); + // We should probably do more logic for trying to reconnect to the arduino + // For now, it should be obvious to people that the arduinos have disconnected + m_threadActive = false; + } + } } bool BTSerialCommunicationManager::ReceiveNextPacket(std::string& buff) { - char nextChar[1]; - do { - int recievedMessageLength = 1; - int recieveResult = recv(m_btClientSocket, nextChar, recievedMessageLength, 0); //if your socket is blocking, this will block until a - if (recieveResult < 0) //a message is recieved. If not, it will return right - { //away - continue; - } - buff += nextChar[0]; - } while (nextChar[0] != '\n' || buff.length() < 1); - - //("Packet Recieved! Length: %i, %s", buff.length(), buff.c_str()); - - return true; + char nextChar[1]; + do { + int recievedMessageLength = 1; + int recieveResult = recv(m_btClientSocket, nextChar, recievedMessageLength, 0); // if your socket is blocking, this will block until a + if (recieveResult < 0) // a message is recieved. If not, it will return right + { // away + continue; + } + buff += nextChar[0]; + } while (nextChar[0] != '\n' || buff.length() < 1); + + //("Packet Recieved! Length: %i, %s", buff.length(), buff.c_str()); + + return true; } -void BTSerialCommunicationManager::Disconnect() { - if (m_isConnected) { - if (m_threadActive) { - m_threadActive = false; - m_serialThread.join(); - } - m_isConnected = false; - //CloseHandle(m_hSerial); - - - //Disconnect - if (shutdown(m_btClientSocket, 2) == SOCKET_ERROR) { - DriverLog("Could not disconnect socket from ESP32. Error %ld", WSAGetLastError()); - } - else - DriverLog("Disconnected from socket successfully."); - } +void BTSerialCommunicationManager::QueueSend(const VRFFBData_t& data) { + std::lock_guard lock(m_writeMutex); + + m_writeString = m_encodingManager->Encode(data); } -//May want to get a heartbeat here instead? -bool BTSerialCommunicationManager::IsConnected() { - return m_isConnected; + +void BTSerialCommunicationManager::Disconnect() { + if (m_isConnected) { + if (m_threadActive) { + m_threadActive = false; + m_serialThread.join(); + } + m_isConnected = false; + // CloseHandle(m_hSerial); + + // Disconnect + if (shutdown(m_btClientSocket, 2) == SOCKET_ERROR) { + DriverLog("Could not disconnect socket from ESP32. Error %ld", WSAGetLastError()); + } else + DriverLog("Disconnected from socket successfully."); + } } +// May want to get a heartbeat here instead? +bool BTSerialCommunicationManager::IsConnected() { return m_isConnected; } /// -/// Gets the bluetooth devices paired with this machine and +/// Gets the bluetooth devices paired with this machine and /// finds an ESP32. If it finds one, its BT address is stored. /// bool BTSerialCommunicationManager::getPairedEsp32BtAddress() { - 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 - }; - 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) { - DriverLog("Could not find any bluetooth devices."); - return false; - } - do { - //wprintf(L"Checking %s.\r\n", btDeviceInfo.szName); - - 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) {// - DriverLog("ESP32 found!\r\n"); - if (btDeviceInfo.fAuthenticated) //I found that if fAuthenticated is true it means the device is paired. - { - DriverLog("ESP32 is authenticated.\r\n"); - m_esp32BtAddress = btDeviceInfo.Address.ullLong; - return true; - } - else { - DriverLog("This ESP32 is not authenticated. Please pair with it first.\r\n"); - } - } - } while (BluetoothFindNextDevice(btDevice, &btDeviceInfo)); //loop through remaining BT devices connected to this machine - - DriverLog("Could not find a paired ESP32 with name %s", m_btSerialConfiguration.name.c_str()); - return false; + 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 + }; + 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) { + DriverLog("Could not find any bluetooth devices."); + 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) { // + DriverLog("ESP32 found!\r\n"); + if (btDeviceInfo.fAuthenticated) // I found that if fAuthenticated is true it means the device is paired. + { + DriverLog("ESP32 is authenticated.\r\n"); + m_esp32BtAddress = btDeviceInfo.Address.ullLong; + return true; + } else { + DriverLog("This ESP32 is not authenticated. Please pair with it first.\r\n"); + } + } + } while (BluetoothFindNextDevice(btDevice, &btDeviceInfo)); // loop through remaining BT devices connected to this machine + + DriverLog("Could not find a paired ESP32 with name %s", m_btSerialConfiguration.name.c_str()); + return false; } -/// -/// Windows sockets need an initialization method called before they are used. -/// bool BTSerialCommunicationManager::startupWindowsSocket() { - WORD wVersionRequested; - WSADATA wsaData; - wVersionRequested = MAKEWORD(2, 2); - int wsaStartupError = WSAStartup(wVersionRequested, &wsaData); //call this before using BT windows socket. - if (wsaStartupError != 0) { - DebugDriverLog("WSAStartup failed with error: %d", wsaStartupError); - return false; - } - return true; + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(2, 2); + int wsaStartupError = WSAStartup(wVersionRequested, &wsaData); // call this before using BT windows socket. + if (wsaStartupError != 0) { + DebugDriverLog("WSAStartup failed with error: %d", wsaStartupError); + return false; + } + return true; } -/// -/// Sets up bluetooth socket to communicate with ESP32. -/// bool BTSerialCommunicationManager::connectToEsp32() { - 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_esp32BtAddress; //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. - { - DriverLog("Could not connect socket to ESP32. Error %ld", WSAGetLastError()); - 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 - DriverLog("Could not set socket to be non-blocking."); - return false; - } - return true; + 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_esp32BtAddress; // 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. + { + DriverLog("Could not connect socket to ESP32. Error %ld", WSAGetLastError()); + 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 + DriverLog("Could not set socket to be non-blocking."); + return false; + } + return true; } bool BTSerialCommunicationManager::sendMessageToEsp32() { - const char* message = "Message from Windows\r\n"; - int sendResult = send(m_btClientSocket, message, (int)strlen(message), 0); //send your message to the BT device - if (sendResult == SOCKET_ERROR) { - DriverLog("Sending to ESP32 failed. Error code %d", WSAGetLastError()); - closesocket(m_btClientSocket); - WSACleanup(); - return false; - } - return true; + std::lock_guard lock(m_writeMutex); + const char* message = m_writeString.c_str(); + //DebugDriverLog("Sending %s to ESP32.", 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) { + DriverLog("Sending to ESP32 failed. Error code %d", WSAGetLastError()); + closesocket(m_btClientSocket); + WSACleanup(); + return false; + } + return true; } \ No newline at end of file diff --git a/src/Communication/SerialCommunicationManager.cpp b/src/Communication/SerialCommunicationManager.cpp index 88dd5bf2..780911f3 100644 --- a/src/Communication/SerialCommunicationManager.cpp +++ b/src/Communication/SerialCommunicationManager.cpp @@ -1,146 +1,151 @@ #include #include + #include "DriverLog.h" void SerialCommunicationManager::Connect() { - //We're not yet connected - m_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) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) { - - DebugDriverLog("Serial error: Handle was not attached. Reason: not available."); - } - else { - DebugDriverLog("Serial error:Received error connecting to port"); - } - } - else { - //If connected we try to set the comm parameters - DCB dcbSerialParams = { 0 }; - - //Try to get the current - if (!GetCommState(m_hSerial, &dcbSerialParams)) { - //If impossible, show an error - DebugDriverLog("Serial error: failed to get current serial parameters!"); - } - else { - //Define serial connection parameters for the arduino board - dcbSerialParams.BaudRate = CBR_115200; - dcbSerialParams.ByteSize = 8; - dcbSerialParams.StopBits = ONESTOPBIT; - dcbSerialParams.Parity = NOPARITY; - - //reset upon establishing a connection - dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; - - //set the parameters and check for their proper application - if (!SetCommState(m_hSerial, &dcbSerialParams)) { - DebugDriverLog("ALERT: Could not set Serial Port parameters"); - } - else { - //If everything went fine we're connected - m_isConnected = true; - //Flush any remaining characters in the buffers - PurgeComm(m_hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR); - } - } - } + // We're not yet connected + m_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) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + DebugDriverLog("Serial error: Handle was not attached. Reason: not available."); + } else { + DebugDriverLog("Serial error:Received error connecting to port"); + } + } else { + // If connected we try to set the comm parameters + DCB dcbSerialParams = {0}; + + // Try to get the current + if (!GetCommState(m_hSerial, &dcbSerialParams)) { + // If impossible, show an error + DebugDriverLog("Serial error: failed to get current serial parameters!"); + } else { + // Define serial connection parameters for the arduino board + dcbSerialParams.BaudRate = CBR_115200; + dcbSerialParams.ByteSize = 8; + dcbSerialParams.StopBits = ONESTOPBIT; + dcbSerialParams.Parity = NOPARITY; + + // reset upon establishing a connection + dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; + + // set the parameters and check for their proper application + if (!SetCommState(m_hSerial, &dcbSerialParams)) { + DebugDriverLog("ALERT: Could not set Serial Port parameters"); + } else { + // If everything went fine we're connected + m_isConnected = true; + // Flush any remaining characters in the buffers + PurgeComm(m_hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR); + } + } + } } void SerialCommunicationManager::BeginListener(const std::function& callback) { - //DebugDriverLog("Begun listener"); - m_threadActive = true; - m_serialThread = std::thread(&SerialCommunicationManager::ListenerThread, this, callback); + // DebugDriverLog("Begun listener"); + m_threadActive = true; + m_serialThread = std::thread(&SerialCommunicationManager::ListenerThread, this, callback); } void SerialCommunicationManager::ListenerThread(const std::function& callback) { - //DebugDriverLog("In listener thread"); - std::this_thread::sleep_for(std::chrono::milliseconds(ARDUINO_WAIT_TIME)); - PurgeBuffer(); - - while (m_threadActive) { - std::string receivedString; - bool readSuccessful = ReceiveNextPacket(receivedString); - - - if (readSuccessful) { - try { - VRCommData_t commData = m_encodingManager->Decode(receivedString); - callback(commData); - } - catch (const std::invalid_argument& ia) { - DriverLog("Received error from encoding manager. Skipping..."); - } - } - else { - DebugDriverLog("Detected that arduino has disconnected! Stopping listener..."); - //We should probably do more logic for trying to reconnect to the arduino - //For now, it should be obvious to people that the arduinos have disconnected - m_threadActive = false; - } - - } + // DebugDriverLog("In listener thread"); + std::this_thread::sleep_for(std::chrono::milliseconds(ARDUINO_WAIT_TIME)); + PurgeBuffer(); + + while (m_threadActive) { + std::string receivedString; + bool readSuccessful = ReceiveNextPacket(receivedString); + + if (readSuccessful) { + try { + VRCommData_t commData = m_encodingManager->Decode(receivedString); + callback(commData); + + Write(); + } catch (const std::invalid_argument& ia) { + DriverLog("Received error from encoding manager. Skipping..."); + } + } else { + DebugDriverLog("Detected that arduino has disconnected! Stopping listener..."); + // We should probably do more logic for trying to reconnect to the arduino + // For now, it should be obvious to people that the arduinos have disconnected + m_threadActive = false; + } + } } bool SerialCommunicationManager::ReceiveNextPacket(std::string& buff) { - DWORD dwCommEvent; - DWORD dwRead = 0; - - if (!SetCommMask(m_hSerial, EV_RXCHAR)) { - DebugDriverLog("Error setting comm mask"); - return false; - } - - char nextChar; - int bytesRead = 0; - if (WaitCommEvent(m_hSerial, &dwCommEvent, NULL)) { - do { - if (ReadFile(m_hSerial, &nextChar, 1, &dwRead, NULL)) { - buff += nextChar; - bytesRead++; - } - else { - DebugDriverLog("Read file error"); - return false; - } - } while (nextChar != '\n'); - } - else { - DebugDriverLog("Error in comm event"); - return false; - } - - return true; + DWORD dwCommEvent; + DWORD dwRead = 0; + + if (!SetCommMask(m_hSerial, EV_RXCHAR)) { + DebugDriverLog("Error setting comm mask"); + return false; + } + + char nextChar; + int bytesRead = 0; + if (WaitCommEvent(m_hSerial, &dwCommEvent, NULL)) { + do { + if (ReadFile(m_hSerial, &nextChar, 1, &dwRead, NULL)) { + buff += nextChar; + bytesRead++; + } else { + DebugDriverLog("Read file error"); + return false; + } + } while (nextChar != '\n'); + } else { + DebugDriverLog("Error in comm event"); + return false; + } + + return true; } -bool SerialCommunicationManager::PurgeBuffer() { - return PurgeComm(m_hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR); + +void SerialCommunicationManager::QueueSend(const VRFFBData_t& data) { + std::lock_guard lock(m_writeMutex); + + m_writeString = m_encodingManager->Encode(data); } -void SerialCommunicationManager::Disconnect() { - if (m_isConnected) { - if (m_threadActive) { - m_threadActive = false; - m_serialThread.join(); - } - m_isConnected = false; - CloseHandle(m_hSerial); +bool SerialCommunicationManager::Write() { + std::lock_guard lock(m_writeMutex); + + const char* buf = m_writeString.c_str(); + + DWORD bytesSend; + if (!WriteFile(this->m_hSerial, (void*)buf, strlen(buf), &bytesSend, 0)) { + ClearCommError(this->m_hSerial, &this->m_errors, &this->m_status); - //Disconnect - } + DebugDriverLog("Error connecting writing to Serial Port."); + return false; + } + + 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(); + } + m_isConnected = false; + CloseHandle(m_hSerial); + + // Disconnect + } } -//May want to get a heartbeat here instead? -bool SerialCommunicationManager::IsConnected() { - return m_isConnected; -} \ No newline at end of file +// May want to get a heartbeat here instead? +bool SerialCommunicationManager::IsConnected() { return m_isConnected; } \ No newline at end of file diff --git a/src/ControllerDiscovery.cpp b/src/ControllerDiscovery.cpp index 2f94a09f..6a92df75 100644 --- a/src/ControllerDiscovery.cpp +++ b/src/ControllerDiscovery.cpp @@ -3,7 +3,9 @@ #include #include "DriverLog.h" - +#include "Pipe.h" +#include "Quaternion.h" +/* std::string GetLastErrorAsString() { // Get the error message ID, if any. DWORD errorMessageID = ::GetLastError(); @@ -28,7 +30,7 @@ std::string GetLastErrorAsString() { LocalFree(messageBuffer); return message; -} +}*/ ControllerDiscoveryPipe::ControllerDiscoveryPipe() : m_listenerActive(false), m_hPipe(0), m_lpPipeInst(0){}; @@ -158,18 +160,17 @@ void ControllerDiscoveryPipe::PipeListenerThread( bool fRead = ReadFileEx(m_lpPipeInst->hPipeInst, &m_lpPipeInst->chRequest, sizeof(ControllerPipeData), (LPOVERLAPPED)m_lpPipeInst, (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine); + if (fRead) break; switch (GetLastError()) { case ERROR_BROKEN_PIPE: + DebugDriverLog("Client disconnected!"); DisconnectAndClose(); PipeListenerThread(callback, role); break; } break; } - case WAIT_IO_COMPLETION: { - break; - } default: { DriverLog("WaitForSingleObjectEx with error: %s.\n", GetLastErrorAsString().c_str()); diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index b7ed2036..da02a855 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -9,58 +9,48 @@ namespace knuckleDevice { } 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 + 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) - : m_configuration(configuration), - m_communicationManager(std::move(communicationManager)), - m_serialNumber(std::move(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) - ); - + : m_configuration(configuration), + m_communicationManager(std::move(communicationManager)), + m_serialNumber(std::move(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)); } +bool KnuckleDeviceDriver::IsRightHand() const { return m_configuration.role == vr::TrackedControllerRole_RightHand; } -bool KnuckleDeviceDriver::IsRightHand() const { - return m_configuration.role == vr::TrackedControllerRole_RightHand; -} +std::string KnuckleDeviceDriver::GetSerialNumber() { return m_serialNumber; } + +bool KnuckleDeviceDriver::IsActive() { return m_hasActivated; } -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; //unique ID for your driver @@ -169,40 +159,47 @@ vr::EVRInitError KnuckleDeviceDriver::Activate(uint32_t unObjectId) { return vr::VRInitError_None; } -//This could do with a rename, its a bit vague as to what it does +// This could do with a rename, its a bit vague as to what it does void KnuckleDeviceDriver::StartDevice() { - m_communicationManager->Connect(); - if (m_communicationManager->IsConnected()) { - m_communicationManager->BeginListener([&](VRCommData_t datas) { - try { - //Compute each finger transform - for (int i = 0; i < NUM_BONES; i++) { - int fingerNum = FingerFromBone(i); - if (fingerNum != -1) { - ComputeBoneFlexion(&m_handTransforms[i], datas.flexion[fingerNum], i, 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::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); + m_ffbProvider = std::make_unique(); + m_ffbProvider->Start( + [&](VRFFBData_t data) { + // Queue the force feedback data for sending. + m_communicationManager->QueueSend(data); + }, + m_configuration.role); + m_communicationManager->Connect(); + if (m_communicationManager->IsConnected()) { + m_communicationManager->BeginListener([&](VRCommData_t datas) { + try { + // Compute each finger transform + for (int i = 0; i < NUM_BONES; i++) { + int fingerNum = FingerFromBone(i); + if (fingerNum != -1) { + ComputeBoneFlexion(&m_handTransforms[i], datas.flexion[fingerNum], i, 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::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); //We don't have a thumb on the index //vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::THUMB], datas.flexion[0], 0); @@ -226,42 +223,38 @@ void KnuckleDeviceDriver::StartDevice() { } }); - } - else { - DebugDriverLog("Device did not connect successfully"); - //Perhaps retry - } + } else { + DebugDriverLog("Device did not connect successfully"); + } } vr::DriverPose_t KnuckleDeviceDriver::GetPose() { - if (m_hasActivated) return m_controllerPose->UpdatePose(); + if (m_hasActivated) return m_controllerPose->UpdatePose(); - vr::DriverPose_t pose = { 0 }; - return pose; + 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)); - } + 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_driverId = vr::k_unTrackedDeviceIndexInvalid; - } + if (m_hasActivated) { + m_communicationManager->Disconnect(); + m_ffbProvider->Stop(); + m_driverId = vr::k_unTrackedDeviceIndexInvalid; + } } -void* KnuckleDeviceDriver::GetComponent(const char* pchComponentNameAndVersion) { - return nullptr; -} +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; - } + if (unResponseBufferSize >= 1) { + pchResponseBuffer[0] = 0; + } } \ No newline at end of file diff --git a/src/Encode/AlphaEncodingManager.cpp b/src/Encode/AlphaEncodingManager.cpp index 8d117d6c..7258032c 100644 --- a/src/Encode/AlphaEncodingManager.cpp +++ b/src/Encode/AlphaEncodingManager.cpp @@ -83,4 +83,22 @@ VRCommData_t AlphaEncodingManager::Decode(std::string input) { ); return commData; -} \ No newline at end of file +} + +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) { + DriverLog("Error decoding string"); + return ""; + } + auto size = static_cast(size_s); + 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 +} + +std::string AlphaEncodingManager::Encode(const VRFFBData_t& data) { + std::string result = string_format("A%dB%dC%dD%dE%d\n", data.thumbCurl, data.indexCurl, data.middleCurl, data.ringCurl, data.pinkyCurl); + return result; +}; \ No newline at end of file diff --git a/src/Encode/LegacyEncodingManager.cpp b/src/Encode/LegacyEncodingManager.cpp index 0c7224b7..86d02840 100644 --- a/src/Encode/LegacyEncodingManager.cpp +++ b/src/Encode/LegacyEncodingManager.cpp @@ -2,31 +2,32 @@ #include #include + #include "DriverLog.h" VRCommData_t LegacyEncodingManager::Decode(std::string input) { - std::string buf; - std::stringstream ss(input); + std::string buf; + std::stringstream ss(input); - std::vector tokens(VRCommDataInputPosition::MAX); - std::fill(tokens.begin(), tokens.begin() + VRCommDataInputPosition::MAX, 0.0f); + std::vector tokens(VRCommDataInputPosition::MAX); + std::fill(tokens.begin(), tokens.begin() + VRCommDataInputPosition::MAX, 0.0f); - short i = 0; - while (getline(ss, buf, '&')) { - tokens[i] = std::stof(buf); - i++; - } + short i = 0; + while (getline(ss, buf, '&')) { + tokens[i] = std::stof(buf); + i++; + } - std::array flexion; - std::array splay; + std::array flexion; + std::array splay; - for (int i = 0; i < 5; i++) { - flexion[i] = tokens[i] / m_maxAnalogValue; - splay[i] = 0.5; - } + for (int i = 0; i < 5; i++) { + flexion[i] = tokens[i] / m_maxAnalogValue; + splay[i] = 0.5; + } - const float joyX = (2 * tokens[VRCommDataInputPosition::JOY_X] / m_maxAnalogValue) - 1; - const float joyY = (2 * tokens[VRCommDataInputPosition::JOY_Y] / m_maxAnalogValue) - 1; + const float joyX = (2 * tokens[VRCommDataInputPosition::JOY_X] / m_maxAnalogValue) - 1; + const float joyY = (2 * tokens[VRCommDataInputPosition::JOY_Y] / m_maxAnalogValue) - 1; VRCommData_t commData( flexion, @@ -42,5 +43,23 @@ VRCommData_t LegacyEncodingManager::Decode(std::string input) { false ); - return commData; -} \ No newline at end of file + return commData; +} + +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) { + DriverLog("Error decoding string"); + return ""; + } + auto size = static_cast(size_s); + 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 +} + +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); + return result; +}; \ No newline at end of file diff --git a/src/ForceFeedback/FFBPipe.cpp b/src/ForceFeedback/FFBPipe.cpp new file mode 100644 index 00000000..b3ddcea7 --- /dev/null +++ b/src/ForceFeedback/FFBPipe.cpp @@ -0,0 +1,214 @@ +#include "ForceFeedback/FFBPipe.h" + +#include + +#include "DriverLog.h" +#include "Pipe.h" + +/*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; + + // Ask Win32 to give us the string version of that message ID. + // The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be). + 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); + + // Copy the error message into a std::string. + std::string message(messageBuffer, size); + + // Free the Win32's string's buffer. + LocalFree(messageBuffer); + + return message; +}*/ + +FFBPipe::FFBPipe() : m_listenerActive(false), m_hPipe(0){}; + +bool FFBPipe::Start(const std::function &callback, vr::ETrackedControllerRole handedness) { + m_listenerActive = true; + m_pipeThread = std::thread(&FFBPipe::PipeListenerThread, this, callback, handedness); + + return true; +} + +VOID WINAPI CompletedReadRoutineFFB(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap) { + LPPIPEINSTFFB lpPipeInst; + BOOL fWrite = FALSE; + + lpPipeInst = (LPPIPEINSTFFB)lpOverLap; + + if ((dwErr == 0) && (cbBytesRead != 0)) { + DebugDriverLog("Received force feedback request: %d", lpPipeInst->chRequest.indexCurl); + lpPipeInst->callback(lpPipeInst->chRequest); + } +} + +// Returns true if pending, false if the operation has completed. +bool FFBPipe::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 + sizeof(VRFFBData_t), // output buffer size + sizeof(VRFFBData_t), // 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 { + DebugDriverLog("Created pipe successfully"); + } + + return ConnectToNewClient(lpo); +} + +bool FFBPipe::ConnectToNewClient(LPOVERLAPPED lpo) { + BOOL fConnected, fPendingIO = FALSE; + + // Start an overlapped connection for this pipe instance. + fConnected = ConnectNamedPipe(&m_hPipe, lpo); + + // Overlapped ConnectNamedPipe should return zero. + if (fConnected) { + printf("ConnectNamedPipe failed with %d.\n", GetLastError()); + return 0; + } + + switch (GetLastError()) { + // The overlapped connection in progress. + case ERROR_IO_PENDING: + fPendingIO = TRUE; + break; + + // Client is already connected, so signal an event. + + case ERROR_PIPE_CONNECTED: + if (SetEvent(lpo->hEvent)) break; + + // If an error occurs during the connect operation... + default: { + printf("ConnectNamedPipe failed with %d.\n", GetLastError()); + return 0; + } + } + return fPendingIO; +} + +void FFBPipe::PipeListenerThread(const std::function &callback, vr::ETrackedControllerRole handedness) { + 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; + } + + std::string pipeName = "\\\\.\\pipe\\vrapplication\\ffb\\curl\\"; + pipeName.append((handedness == vr::ETrackedControllerRole::TrackedControllerRole_RightHand) ? "right" : "left"); + DebugDriverLog("Creating pipe: %s", pipeName.c_str()); + + fPendingIO = CreateAndConnectInstance(&oConnect, pipeName); + + while (m_listenerActive) { + dwWait = WaitForSingleObjectEx(hConnectEvent, // event object to wait for + INFINITE, // waits indefinitely + TRUE); // alertable wait enabled + switch (dwWait) { + // The wait conditions are satisfied by a completed connect + // operation. + case 0: { + // If an operation is pending, get the result of the + // connect operation. + + 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; + } + } + + // Allocate storage for this instance. + m_lpPipeInst = (LPPIPEINSTFFB)GlobalAlloc(GPTR, sizeof(PIPEINSTFFB)); + + 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, sizeof(VRFFBData_t), (LPOVERLAPPED)m_lpPipeInst, + (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutineFFB); + if (fRead) break; + + switch (GetLastError()) { + case ERROR_BROKEN_PIPE: + DebugDriverLog("Client disconnected!"); + DisconnectAndClose(); + PipeListenerThread(callback, handedness); + break; + } + } + + break; + + // The wait is satisfied by a completed read or write + // operation. This allows the system to execute the + // completion routine. + 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 FFBPipe::DisconnectAndClose() { + DebugDriverLog("Closing pipe..."); + if (m_listenerActive) m_listenerActive = false; + + if (!DisconnectNamedPipe(m_lpPipeInst->hPipeInst)) { + DebugDriverLog("DisconnectNamedPipe failed with error: %s.\n", GetLastErrorAsString().c_str()); + } + + // Close the handle to the pipe instance. + CloseHandle(m_lpPipeInst->hPipeInst); + + // Release the storage for the pipe instance. + if (m_lpPipeInst != NULL) GlobalFree(m_lpPipeInst); +} + +void FFBPipe::Stop() { + DriverLog("Disconnecting FFB"); + m_listenerActive = false; + m_pipeThread.join(); + DisconnectAndClose(); +} \ No newline at end of file diff --git a/src/Pipe.cpp b/src/Pipe.cpp new file mode 100644 index 00000000..75dfa07e --- /dev/null +++ b/src/Pipe.cpp @@ -0,0 +1,40 @@ +#include "Pipe.h" + +#include + +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; + + // Ask Win32 to give us the string version of that message ID. + // The parameters we pass in, tell Win32 to create the buffer that holds the message for us + // (because we don't yet know how long the message string will be). + 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); + + // Copy the error message into a std::string. + std::string message(messageBuffer, size); + + // Free the Win32's string's buffer. + LocalFree(messageBuffer); + + return message; +} + +/* +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); + } +} +*/ \ No newline at end of file From da98dddcf6ee639c4a3a1680fbcfb4f2ee38ca6e Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sat, 24 Jul 2021 18:19:27 +0100 Subject: [PATCH 19/27] Cleanup named pipes (#110) * remove unneeded files * make static --- include/Pipe.h | 8 ------- libraries/asio | 1 - src/ControllerDiscovery.cpp | 7 +++--- src/ForceFeedback/FFBPipe.cpp | 5 ++--- src/Pipe.cpp | 40 ----------------------------------- 5 files changed, 5 insertions(+), 56 deletions(-) delete mode 100644 include/Pipe.h delete mode 160000 libraries/asio delete mode 100644 src/Pipe.cpp diff --git a/include/Pipe.h b/include/Pipe.h deleted file mode 100644 index 7d6f3004..00000000 --- a/include/Pipe.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -#include -#include -#include - -std::string GetLastErrorAsString(); \ No newline at end of file diff --git a/libraries/asio b/libraries/asio deleted file mode 160000 index 57577c6d..00000000 --- a/libraries/asio +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 57577c6db46a4e2de5351af2b185bf52696699a9 diff --git a/src/ControllerDiscovery.cpp b/src/ControllerDiscovery.cpp index 6a92df75..3369e820 100644 --- a/src/ControllerDiscovery.cpp +++ b/src/ControllerDiscovery.cpp @@ -3,10 +3,9 @@ #include #include "DriverLog.h" -#include "Pipe.h" #include "Quaternion.h" -/* -std::string GetLastErrorAsString() { + +static std::string GetLastErrorAsString() { // Get the error message ID, if any. DWORD errorMessageID = ::GetLastError(); if (errorMessageID == 0) { @@ -30,7 +29,7 @@ std::string GetLastErrorAsString() { LocalFree(messageBuffer); return message; -}*/ +} ControllerDiscoveryPipe::ControllerDiscoveryPipe() : m_listenerActive(false), m_hPipe(0), m_lpPipeInst(0){}; diff --git a/src/ForceFeedback/FFBPipe.cpp b/src/ForceFeedback/FFBPipe.cpp index b3ddcea7..eb279d41 100644 --- a/src/ForceFeedback/FFBPipe.cpp +++ b/src/ForceFeedback/FFBPipe.cpp @@ -3,9 +3,8 @@ #include #include "DriverLog.h" -#include "Pipe.h" -/*std::string GetLastErrorAsString() { +static std::string GetLastErrorAsString() { // Get the error message ID, if any. DWORD errorMessageID = ::GetLastError(); if (errorMessageID == 0) { @@ -26,7 +25,7 @@ LocalFree(messageBuffer); return message; -}*/ +} FFBPipe::FFBPipe() : m_listenerActive(false), m_hPipe(0){}; diff --git a/src/Pipe.cpp b/src/Pipe.cpp deleted file mode 100644 index 75dfa07e..00000000 --- a/src/Pipe.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Pipe.h" - -#include - -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; - - // Ask Win32 to give us the string version of that message ID. - // The parameters we pass in, tell Win32 to create the buffer that holds the message for us - // (because we don't yet know how long the message string will be). - 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); - - // Copy the error message into a std::string. - std::string message(messageBuffer, size); - - // Free the Win32's string's buffer. - LocalFree(messageBuffer); - - return message; -} - -/* -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); - } -} -*/ \ No newline at end of file From ec3b94a544c368916a7d2c805ca61a38503b6cb2 Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sat, 24 Jul 2021 23:16:53 +0100 Subject: [PATCH 20/27] Refactor Named Pipes (#111) * remove unneeded files * make static * refactor named pipes into utility class * remove unnecessary function * make static and fix invalid pipe name --- include/ControllerDiscovery.h | 39 +-- include/ControllerPose.h | 2 +- include/DeviceDriver/KnuckleDriver.h | 4 +- include/Encode/EncodingManager.h | 2 +- include/Encode/LegacyEncodingManager.h | 2 +- include/ForceFeedback.h | 31 ++ include/ForceFeedback/FFBPipe.h | 49 ---- include/Util/NamedPipe.h | 40 +++ src/ControllerDiscovery.cpp | 208 +------------ src/ControllerPose.cpp | 14 +- src/DeviceDriver/KnuckleDriver.cpp | 277 ++++++++++-------- src/ForceFeedback.cpp | 22 ++ .../FFBPipe.cpp => Util/NamedPipe.cpp} | 106 +++---- 13 files changed, 313 insertions(+), 483 deletions(-) create mode 100644 include/ForceFeedback.h delete mode 100644 include/ForceFeedback/FFBPipe.h create mode 100644 include/Util/NamedPipe.h create mode 100644 src/ForceFeedback.cpp rename src/{ForceFeedback/FFBPipe.cpp => Util/NamedPipe.cpp} (58%) diff --git a/include/ControllerDiscovery.h b/include/ControllerDiscovery.h index 0a2509f1..063286d6 100644 --- a/include/ControllerDiscovery.h +++ b/include/ControllerDiscovery.h @@ -1,44 +1,23 @@ #pragma once -#include - -#include +#include #include -#include - #include "openvr_driver.h" +#include "Util/NamedPipe.h" -struct ControllerPipeData { +struct ControllerDiscoveryPipeData_t { short controllerId; }; -typedef struct { - OVERLAPPED oOverlap; - HANDLE hPipeInst; - ControllerPipeData chRequest; - DWORD cbRead; - DWORD cbToWrite; - std::function callback; -} PIPEINST, *LPPIPEINST; -class ControllerDiscoveryPipe { +class ControllerDiscovery { public: - ControllerDiscoveryPipe(); - ~ControllerDiscoveryPipe(); + ControllerDiscovery(vr::ETrackedControllerRole role, std::function callback); - bool Start(const std::function& callback, vr::ETrackedControllerRole role); + void Start(); void Stop(); private: - void PipeListenerThread(const std::function& callback, - vr::ETrackedControllerRole role); - void DisconnectAndClose(); - bool CreateAndConnectInstance(LPOVERLAPPED lpo, std::string& pipeName); - bool ConnectToNewClient(LPOVERLAPPED lpo); - HANDLE m_hPipe; - - std::thread m_pipeThread; - - std::atomic m_listenerActive; - std::atomic m_clientConnected; - LPPIPEINST m_lpPipeInst; + vr::ETrackedControllerRole m_role; + std::unique_ptr m_pipe; + std::function m_callback; }; \ No newline at end of file diff --git a/include/ControllerPose.h b/include/ControllerPose.h index 3cab840e..1358ab43 100644 --- a/include/ControllerPose.h +++ b/include/ControllerPose.h @@ -35,6 +35,6 @@ class ControllerPose { bool isRightHand(); - std::unique_ptr m_controllerDiscoverer; + std::unique_ptr m_controllerDiscoverer; std::unique_ptr m_calibration; }; \ No newline at end of file diff --git a/include/DeviceDriver/KnuckleDriver.h b/include/DeviceDriver/KnuckleDriver.h index cd578506..40ced7b3 100644 --- a/include/DeviceDriver/KnuckleDriver.h +++ b/include/DeviceDriver/KnuckleDriver.h @@ -11,7 +11,7 @@ #include "DeviceConfiguration.h" #include "DeviceDriver/DeviceDriver.h" #include "Encode/LegacyEncodingManager.h" -#include "ForceFeedback/FFBPipe.h" +#include "ForceFeedback.h" class KnuckleDeviceDriver : public IDeviceDriver { public: @@ -48,5 +48,5 @@ class KnuckleDeviceDriver : public IDeviceDriver { std::string m_serialNumber; std::unique_ptr m_controllerPose; - std::unique_ptr m_ffbProvider; + std::unique_ptr m_ffbProvider; }; diff --git a/include/Encode/EncodingManager.h b/include/Encode/EncodingManager.h index 8e7c6575..0dbb82cd 100644 --- a/include/Encode/EncodingManager.h +++ b/include/Encode/EncodingManager.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include "ForceFeedback/FFBPipe.h" +#include "ForceFeedback.h" struct VRCommData_t { VRCommData_t(std::array flexion, std::array splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool calibrate) : diff --git a/include/Encode/LegacyEncodingManager.h b/include/Encode/LegacyEncodingManager.h index 39d88816..5f84e382 100644 --- a/include/Encode/LegacyEncodingManager.h +++ b/include/Encode/LegacyEncodingManager.h @@ -1,7 +1,7 @@ #pragma once #include -#include "ForceFeedback/FFBPipe.h" +#include "ForceFeedback.h" class LegacyEncodingManager : public IEncodingManager { public: diff --git a/include/ForceFeedback.h b/include/ForceFeedback.h new file mode 100644 index 00000000..5d49180c --- /dev/null +++ b/include/ForceFeedback.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#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); + void Start(); + void Stop(); + + private: + std::function m_callback; + vr::ETrackedControllerRole m_role; + + std::unique_ptr m_pipe; +}; \ No newline at end of file diff --git a/include/ForceFeedback/FFBPipe.h b/include/ForceFeedback/FFBPipe.h deleted file mode 100644 index 474fd35b..00000000 --- a/include/ForceFeedback/FFBPipe.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include "openvr_driver.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; -}; -typedef struct { - OVERLAPPED oOverlap; - HANDLE hPipeInst; - VRFFBData_t chRequest; - DWORD cbRead; - DWORD cbToWrite; - std::function callback; -} PIPEINSTFFB, *LPPIPEINSTFFB; - -class FFBPipe { - public: - FFBPipe(); - bool Start(const std::function& callback, vr::ETrackedControllerRole handedness); - void Stop(); - - private: - void PipeListenerThread(const std::function& callback, vr::ETrackedControllerRole handedness); - void DisconnectAndClose(); - bool CreateAndConnectInstance(LPOVERLAPPED lpo, std::string& pipeName); - bool ConnectToNewClient(LPOVERLAPPED lpo); - HANDLE m_hPipe; - - std::thread m_pipeThread; - - std::atomic m_listenerActive; - std::atomic m_clientConnected; - - LPPIPEINSTFFB m_lpPipeInst; -}; \ No newline at end of file diff --git a/include/Util/NamedPipe.h b/include/Util/NamedPipe.h new file mode 100644 index 00000000..750a3d5a --- /dev/null +++ b/include/Util/NamedPipe.h @@ -0,0 +1,40 @@ +#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 DisconnectAndClose(); + 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/src/ControllerDiscovery.cpp b/src/ControllerDiscovery.cpp index 3369e820..3e8f76cc 100644 --- a/src/ControllerDiscovery.cpp +++ b/src/ControllerDiscovery.cpp @@ -1,204 +1,22 @@ #include "ControllerDiscovery.h" -#include - #include "DriverLog.h" -#include "Quaternion.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; - - // Ask Win32 to give us the string version of that message ID. - // The parameters we pass in, tell Win32 to create the buffer that holds the message for us - // (because we don't yet know how long the message string will be). - 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); - - // Copy the error message into a std::string. - std::string message(messageBuffer, size); - - // Free the Win32's string's buffer. - LocalFree(messageBuffer); - - return message; -} - -ControllerDiscoveryPipe::ControllerDiscoveryPipe() - : m_listenerActive(false), m_hPipe(0), m_lpPipeInst(0){}; - -bool ControllerDiscoveryPipe::Start(const std::function &callback, - vr::ETrackedControllerRole role) { - m_listenerActive = true; - m_pipeThread = std::thread(&ControllerDiscoveryPipe::PipeListenerThread, this, callback, role); - - return true; -} - -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); - } -} - -// Returns true if pending, false if the operation has completed. -bool ControllerDiscoveryPipe::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 - sizeof(ControllerPipeData), // output buffer size - sizeof(ControllerPipeData), // 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 { - DebugDriverLog("Created pipe successfully"); - } - - return ConnectToNewClient(lpo); -} - -bool ControllerDiscoveryPipe::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; - default: { - DriverLog("ConnectNamedPipe failed with: %s", GetLastErrorAsString().c_str()); - return 0; - } - } - return fPendingIO; -} - -void ControllerDiscoveryPipe::PipeListenerThread( - const std::function &callback, vr::ETrackedControllerRole role) { - 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; - } - - std::string pipeName; - - if (role == vr::ETrackedControllerRole::TrackedControllerRole_LeftHand) { - pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\left"; - } else { - pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\right"; - } - DebugDriverLog("Creating pipe: %s", pipeName.c_str()); - - fPendingIO = CreateAndConnectInstance(&oConnect, 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, - sizeof(ControllerPipeData), (LPOVERLAPPED)m_lpPipeInst, - (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine); - if (fRead) break; - - switch (GetLastError()) { - case ERROR_BROKEN_PIPE: - DebugDriverLog("Client disconnected!"); - DisconnectAndClose(); - PipeListenerThread(callback, role); - break; - } - break; - } - - default: { - DriverLog("WaitForSingleObjectEx with error: %s.\n", GetLastErrorAsString().c_str()); - return; - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } -} -void ControllerDiscoveryPipe::DisconnectAndClose() { - DebugDriverLog("Closing pipe..."); - if (m_listenerActive) m_listenerActive = false; +ControllerDiscovery::ControllerDiscovery(vr::ETrackedControllerRole role, std::function callback) + : m_role(role), m_callback(std::move(callback)) { - if (!DisconnectNamedPipe(m_lpPipeInst->hPipeInst)) { - DebugDriverLog("DisconnectNamedPipe failed with error: %s.\n", GetLastErrorAsString().c_str()); - } + std::string pipeName = "\\\\.\\pipe\\vrapplication\\discovery\\" + std::string(role == vr::ETrackedControllerRole::TrackedControllerRole_RightHand ? "right" : "left"); - CloseHandle(m_lpPipeInst->hPipeInst); + m_pipe = std::make_unique(pipeName, sizeof(ControllerDiscoveryPipeData_t)); +}; - // Release the storage for the pipe instance. - if (m_lpPipeInst != NULL) GlobalFree(m_lpPipeInst); -} +void ControllerDiscovery::Start() { + m_pipe->Start([&](LPVOID data) { + ControllerDiscoveryPipeData_t *controllerPipeData = (ControllerDiscoveryPipeData_t *)data; -void ControllerDiscoveryPipe::Stop() { - DriverLog("Disconnecting controller pipe..."); - m_listenerActive = false; - m_pipeThread.join(); - DisconnectAndClose(); -} + ControllerDiscoveryPipeData_t result(*controllerPipeData); + m_callback(result); + }); +}; -ControllerDiscoveryPipe::~ControllerDiscoveryPipe() { Stop(); }; \ No newline at end of file +void ControllerDiscovery::Stop() { m_pipe->Stop(); }; \ No newline at end of file diff --git a/src/ControllerPose.cpp b/src/ControllerPose.cpp index fd9509bf..f39b1fdc 100644 --- a/src/ControllerPose.cpp +++ b/src/ControllerPose.cpp @@ -16,14 +16,12 @@ ControllerPose::ControllerPose(vr::ETrackedControllerRole shadowDeviceOfRole, if (m_poseConfiguration.controllerOverrideEnabled) { m_shadowControllerId = m_poseConfiguration.controllerIdOverride; } else { - m_controllerDiscoverer = std::make_unique(); - - m_controllerDiscoverer->Start( - [&](ControllerPipeData data) { - m_shadowControllerId = data.controllerId; - DebugDriverLog("Received message! %i", data.controllerId); - }, - m_shadowDeviceOfRole); + m_controllerDiscoverer = std::make_unique(shadowDeviceOfRole, [&](ControllerDiscoveryPipeData_t data) { + m_shadowControllerId = data.controllerId; + DriverLog("Received controller id from overlay: %i", data.controllerId); + }); + + m_controllerDiscoverer->Start(); } m_calibration = std::make_unique(); } diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index da02a855..0def27c2 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -5,7 +5,7 @@ #include "DriverLog.h" namespace knuckleDevice { - const char* c_deviceManufacturer = "LucasVRTech&Danwillm"; +const char* c_deviceManufacturer = "LucasVRTech&Danwillm"; } enum ComponentIndex : int { @@ -52,122 +52,146 @@ 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; //unique ID for your driver - m_controllerPose = std::make_unique(m_configuration.role, std::string(knuckleDevice::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); - 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); - vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceIsCharging_Bool, false); - vr::VRProperties()->SetFloatProperty(props, vr::Prop_DeviceBatteryPercentage_Float, 1.f); // Always charged - - vr::HmdMatrix34_t l_matrix = { -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, -1.f, 0.f, 0.f }; - vr::VRProperties()->SetProperty(props, vr::Prop_StatusDisplayTransform_Matrix34, &l_matrix, sizeof(vr::HmdMatrix34_t), vr::k_unHmdMatrix34PropertyTag); - - vr::VRProperties()->SetBoolProperty(props, vr::Prop_Firmware_UpdateAvailable_Bool, false); - vr::VRProperties()->SetBoolProperty(props, vr::Prop_Firmware_ManualUpdate_Bool, false); - 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()->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()->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()->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, knuckleDevice::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_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); - vr::VRProperties()->SetUint64Property(props, vr::Prop_FirmwareVersion_Uint64, 1562916277U); - vr::VRProperties()->SetUint64Property(props, vr::Prop_FPGAVersion_Uint64, 538U); - vr::VRProperties()->SetUint64Property(props, vr::Prop_VRCVersion_Uint64, 1562916277U); - vr::VRProperties()->SetUint64Property(props, vr::Prop_RadioVersion_Uint64, 1562882729U); - 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_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()->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, - isRightHand ? rightOpenPose : leftOpenPose, - NUM_BONES, - &m_skeletalComponentHandle); - - if (error != vr::VRInputError_None) { - DebugDriverLog("CreateSkeletonComponent failed. Error: %s\n", error); - } - - StartDevice(); - - m_hasActivated = true; - - return vr::VRInitError_None; + const bool isRightHand = IsRightHand(); + m_driverId = unObjectId; // unique ID for your driver + m_controllerPose = std::make_unique(m_configuration.role, std::string(knuckleDevice::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); + 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); + vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceIsCharging_Bool, false); + vr::VRProperties()->SetFloatProperty(props, vr::Prop_DeviceBatteryPercentage_Float, 1.f); // Always charged + + vr::HmdMatrix34_t l_matrix = {-1.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, -1.f, 0.f, 0.f}; + vr::VRProperties()->SetProperty(props, vr::Prop_StatusDisplayTransform_Matrix34, &l_matrix, sizeof(vr::HmdMatrix34_t), vr::k_unHmdMatrix34PropertyTag); + + vr::VRProperties()->SetBoolProperty(props, vr::Prop_Firmware_UpdateAvailable_Bool, false); + vr::VRProperties()->SetBoolProperty(props, vr::Prop_Firmware_ManualUpdate_Bool, false); + 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()->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()->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()->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, knuckleDevice::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_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); + vr::VRProperties()->SetUint64Property(props, vr::Prop_FirmwareVersion_Uint64, 1562916277U); + vr::VRProperties()->SetUint64Property(props, vr::Prop_FPGAVersion_Uint64, 538U); + vr::VRProperties()->SetUint64Property(props, vr::Prop_VRCVersion_Uint64, 1562916277U); + vr::VRProperties()->SetUint64Property(props, vr::Prop_RadioVersion_Uint64, 1562882729U); + 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_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()->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, isRightHand ? rightOpenPose : leftOpenPose, NUM_BONES, &m_skeletalComponentHandle); + + if (error != vr::VRInputError_None) { + DebugDriverLog("CreateSkeletonComponent failed. Error: %s\n", error); + } + + StartDevice(); + + m_hasActivated = true; + + return vr::VRInitError_None; } // This could do with a rename, its a bit vague as to what it does void KnuckleDeviceDriver::StartDevice() { - m_ffbProvider = std::make_unique(); - m_ffbProvider->Start( + m_ffbProvider = std::make_unique( [&](VRFFBData_t data) { // Queue the force feedback data for sending. m_communicationManager->QueueSend(data); }, m_configuration.role); + + m_ffbProvider->Start(); m_communicationManager->Connect(); if (m_communicationManager->IsConnected()) { m_communicationManager->BeginListener([&](VRCommData_t datas) { @@ -201,27 +225,22 @@ void KnuckleDeviceDriver::StartDevice() { vr::VRDriverInput()->UpdateBooleanComponent(m_inputComponentHandles[ComponentIndex::GRIP_TOUCH], datas.grab, 0); vr::VRDriverInput()->UpdateScalarComponent(m_inputComponentHandles[ComponentIndex::GRIP_VALUE], datas.grab, 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->FinishCalibration(); - } - } - catch (const std::exception& e) { - DebugDriverLog("Exception caught while parsing comm data"); - } - }); + // 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->FinishCalibration(); + } + } catch (const std::exception& e) { + DebugDriverLog("Exception caught while parsing comm data"); + } + }); } else { DebugDriverLog("Device did not connect successfully"); diff --git a/src/ForceFeedback.cpp b/src/ForceFeedback.cpp new file mode 100644 index 00000000..ffd2a5bc --- /dev/null +++ b/src/ForceFeedback.cpp @@ -0,0 +1,22 @@ +#include "ForceFeedback.h" + +#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)); +}; + +void FFBListener::Start() { + m_pipe->Start([&](LPVOID data) { + VRFFBData_t *ffbData = (VRFFBData_t *)data; + + VRFFBData_t result(*ffbData); + m_callback(result); + }); +} + +void FFBListener::Stop() { m_pipe->Stop(); }; \ No newline at end of file diff --git a/src/ForceFeedback/FFBPipe.cpp b/src/Util/NamedPipe.cpp similarity index 58% rename from src/ForceFeedback/FFBPipe.cpp rename to src/Util/NamedPipe.cpp index eb279d41..28c1b76a 100644 --- a/src/ForceFeedback/FFBPipe.cpp +++ b/src/Util/NamedPipe.cpp @@ -1,4 +1,4 @@ -#include "ForceFeedback/FFBPipe.h" +#include "Util/NamedPipe.h" #include @@ -7,49 +7,44 @@ 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; - - // Ask Win32 to give us the string version of that message ID. - // The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be). 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); - // Copy the error message into a std::string. std::string message(messageBuffer, size); - // Free the Win32's string's buffer. LocalFree(messageBuffer); return message; -} - -FFBPipe::FFBPipe() : m_listenerActive(false), m_hPipe(0){}; +}; -bool FFBPipe::Start(const std::function &callback, vr::ETrackedControllerRole handedness) { - m_listenerActive = true; - m_pipeThread = std::thread(&FFBPipe::PipeListenerThread, this, callback, handedness); - - return true; -} - -VOID WINAPI CompletedReadRoutineFFB(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap) { - LPPIPEINSTFFB lpPipeInst; +static VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap) { + LPPIPEINST lpPipeInst; BOOL fWrite = FALSE; - lpPipeInst = (LPPIPEINSTFFB)lpOverLap; + lpPipeInst = (LPPIPEINST)lpOverLap; if ((dwErr == 0) && (cbBytesRead != 0)) { - DebugDriverLog("Received force feedback request: %d", lpPipeInst->chRequest.indexCurl); - lpPipeInst->callback(lpPipeInst->chRequest); + 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 FFBPipe::CreateAndConnectInstance(LPOVERLAPPED lpo, std::string &pipeName) { +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 @@ -57,58 +52,51 @@ bool FFBPipe::CreateAndConnectInstance(LPOVERLAPPED lpo, std::string &pipeName) PIPE_READMODE_MESSAGE | // message read mode PIPE_WAIT, // blocking mode PIPE_UNLIMITED_INSTANCES, // unlimited instances - sizeof(VRFFBData_t), // output buffer size - sizeof(VRFFBData_t), // input buffer size + m_pipeSize, // output buffer size + 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 { - DebugDriverLog("Created pipe successfully"); + DriverLog("Pipe created successfully: %s", m_pipeName.c_str()); } return ConnectToNewClient(lpo); } -bool FFBPipe::ConnectToNewClient(LPOVERLAPPED lpo) { +bool NamedPipeUtil::ConnectToNewClient(LPOVERLAPPED lpo) { BOOL fConnected, fPendingIO = FALSE; // Start an overlapped connection for this pipe instance. fConnected = ConnectNamedPipe(&m_hPipe, lpo); - // Overlapped ConnectNamedPipe should return zero. if (fConnected) { - printf("ConnectNamedPipe failed with %d.\n", GetLastError()); + DriverLog("ConnectNamedPipe failed with %c.\n", GetLastErrorAsString().c_str()); return 0; } switch (GetLastError()) { - // The overlapped connection in progress. case ERROR_IO_PENDING: fPendingIO = TRUE; break; - // Client is already connected, so signal an event. - case ERROR_PIPE_CONNECTED: if (SetEvent(lpo->hEvent)) break; - - // If an error occurs during the connect operation... default: { - printf("ConnectNamedPipe failed with %d.\n", GetLastError()); + DriverLog("ConnectNamedPipe failed with: %s", GetLastErrorAsString().c_str()); return 0; } } return fPendingIO; } -void FFBPipe::PipeListenerThread(const std::function &callback, vr::ETrackedControllerRole handedness) { +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 @@ -119,23 +107,16 @@ void FFBPipe::PipeListenerThread(const std::function &callbac return; } - std::string pipeName = "\\\\.\\pipe\\vrapplication\\ffb\\curl\\"; - pipeName.append((handedness == vr::ETrackedControllerRole::TrackedControllerRole_RightHand) ? "right" : "left"); - DebugDriverLog("Creating pipe: %s", pipeName.c_str()); + DriverLog("Creating pipe: %s", m_pipeName.c_str()); - fPendingIO = CreateAndConnectInstance(&oConnect, pipeName); + 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) { - // The wait conditions are satisfied by a completed connect - // operation. case 0: { - // If an operation is pending, get the result of the - // connect operation. - if (fPendingIO) { fSuccess = GetOverlappedResult(m_hPipe, // pipe handle &oConnect, // OVERLAPPED structure @@ -146,9 +127,7 @@ void FFBPipe::PipeListenerThread(const std::function &callbac return; } } - - // Allocate storage for this instance. - m_lpPipeInst = (LPPIPEINSTFFB)GlobalAlloc(GPTR, sizeof(PIPEINSTFFB)); + m_lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST)); if (m_lpPipeInst == NULL) { DriverLog("GlobalAlloc failed with error: %s.\n", GetLastErrorAsString().c_str()); @@ -159,25 +138,18 @@ void FFBPipe::PipeListenerThread(const std::function &callbac m_lpPipeInst->cbToWrite = 0; m_lpPipeInst->callback = callback; - bool fRead = ReadFileEx(m_lpPipeInst->hPipeInst, &m_lpPipeInst->chRequest, sizeof(VRFFBData_t), (LPOVERLAPPED)m_lpPipeInst, - (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutineFFB); + + bool fRead = + ReadFileEx(m_lpPipeInst->hPipeInst, &m_lpPipeInst->chRequest, m_pipeSize, (LPOVERLAPPED)m_lpPipeInst, (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine); if (fRead) break; switch (GetLastError()) { case ERROR_BROKEN_PIPE: - DebugDriverLog("Client disconnected!"); + DriverLog("Detected that a client disconnected for pipe: %s", m_pipeName.c_str()); DisconnectAndClose(); - PipeListenerThread(callback, handedness); + PipeListenerThread(callback); break; } - } - - break; - - // The wait is satisfied by a completed read or write - // operation. This allows the system to execute the - // completion routine. - case WAIT_IO_COMPLETION: { break; } @@ -190,24 +162,24 @@ void FFBPipe::PipeListenerThread(const std::function &callbac } } -void FFBPipe::DisconnectAndClose() { - DebugDriverLog("Closing pipe..."); +void NamedPipeUtil::DisconnectAndClose() { + DriverLog("Closing pipe: %s", m_pipeName.c_str()); if (m_listenerActive) m_listenerActive = false; if (!DisconnectNamedPipe(m_lpPipeInst->hPipeInst)) { - DebugDriverLog("DisconnectNamedPipe failed with error: %s.\n", GetLastErrorAsString().c_str()); + DriverLog("DisconnectNamedPipe failed with error: %s.\n", GetLastErrorAsString().c_str()); } - // Close the handle to the pipe instance. CloseHandle(m_lpPipeInst->hPipeInst); // Release the storage for the pipe instance. if (m_lpPipeInst != NULL) GlobalFree(m_lpPipeInst); } -void FFBPipe::Stop() { - DriverLog("Disconnecting FFB"); +void NamedPipeUtil::Stop() { m_listenerActive = false; m_pipeThread.join(); DisconnectAndClose(); -} \ No newline at end of file +} + +NamedPipeUtil::~NamedPipeUtil() { Stop(); }; \ No newline at end of file From 0fe70d021228f592599324a085698e408fad5ce2 Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Thu, 29 Jul 2021 14:53:32 +0100 Subject: [PATCH 21/27] add missing library (#112) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7dddd4a..7ddb365b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ add_library("${OPENGLOVE_PROJECT}" SHARED "${HEADERS}" "${SOURCES}") target_include_directories("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_INCLUDE_DIR}") target_include_directories("${OPENGLOVE_PROJECT}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/") -target_link_libraries("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_LIB}" wsock32.lib ws2_32.lib Bthprops.lib) +target_link_libraries("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_LIB}" setupapi wsock32 ws2_32 bthprops) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include" PREFIX "Header Files" FILES ${HEADERS}) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Source Files" FILES ${SOURCES}) From feb7a987816ddfda622dc6d9024101cc2f573323 Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Sat, 31 Jul 2021 22:29:40 +0100 Subject: [PATCH 22/27] Fix inconsistent manufacturer name causing issues with lucid glove driver discovery (#113) Changes manufacturer name to "LucidVR" --- overlay/main.cpp | 2 +- src/DeviceDriver/KnuckleDriver.cpp | 8 +- src/DeviceDriver/LucidGloveDriver.cpp | 284 ++++++++++++-------------- 3 files changed, 140 insertions(+), 154 deletions(-) diff --git a/overlay/main.cpp b/overlay/main.cpp index 0c05966a..9a62d066 100644 --- a/overlay/main.cpp +++ b/overlay/main.cpp @@ -6,7 +6,7 @@ std::atomic appActive = true; -const std::string ourManufacturer = "LucasVRTech&Danwillm"; +const std::string ourManufacturer = "LucidVR"; std::string GetLastErrorAsString() { DWORD errorMessageID = ::GetLastError(); diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index 0def27c2..6b8f38c9 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -4,9 +4,7 @@ #include "DriverLog.h" -namespace knuckleDevice { -const char* c_deviceManufacturer = "LucasVRTech&Danwillm"; -} +static const char* c_deviceManufacturer = "LucidVR"; enum ComponentIndex : int { SYSTEM_CLICK, @@ -54,7 +52,7 @@ bool KnuckleDeviceDriver::IsActive() { return m_hasActivated; } vr::EVRInitError KnuckleDeviceDriver::Activate(uint32_t unObjectId) { const bool isRightHand = IsRightHand(); m_driverId = unObjectId; // unique ID for your driver - m_controllerPose = std::make_unique(m_configuration.role, std::string(knuckleDevice::c_deviceManufacturer), m_configuration.poseConfiguration); + 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 @@ -90,7 +88,7 @@ vr::EVRInitError KnuckleDeviceDriver::Activate(uint32_t unObjectId) { 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, knuckleDevice::c_deviceManufacturer); + 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_HardwareRevision_String, "product 17 rev 14.1.9 lot 2019/4/20 0"); diff --git a/src/DeviceDriver/LucidGloveDriver.cpp b/src/DeviceDriver/LucidGloveDriver.cpp index 776cff95..5db623bb 100644 --- a/src/DeviceDriver/LucidGloveDriver.cpp +++ b/src/DeviceDriver/LucidGloveDriver.cpp @@ -2,195 +2,183 @@ #include "DriverLog.h" -namespace lucidGlove { - const char* c_deviceManufacturer = "Lucas_VRTech&Danwillm"; - const char* c_deviceControllerType = "lucidgloves"; - const char* c_deviceModelNumber = "lucidgloves1"; - const char* c_basePosePath = "/pose/raw"; - const char* c_inputProfilePath = "{lucidgloves}/input/openglove_profile.json"; - const char* c_renderModelPath = "{lucidgloves}/rendermodels/lucidgloves"; - -} +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_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 }; -LucidGloveDeviceDriver::LucidGloveDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, std::string serialNumber) - : m_configuration(configuration), - m_communicationManager(std::move(communicationManager)), - 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(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, + std::string serialNumber) + : m_configuration(configuration), m_communicationManager(std::move(communicationManager)), 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)); } -bool LucidGloveDeviceDriver::IsRightHand() const { - return m_configuration.role == vr::TrackedControllerRole_RightHand; -} +bool LucidGloveDeviceDriver::IsRightHand() const { return m_configuration.role == vr::TrackedControllerRole_RightHand; } + +std::string LucidGloveDeviceDriver::GetSerialNumber() { return m_serialNumber; } + +bool LucidGloveDeviceDriver::IsActive() { return m_hasActivated; } -std::string LucidGloveDeviceDriver::GetSerialNumber() { - return m_serialNumber; -} -bool LucidGloveDeviceDriver::IsActive() { - return m_hasActivated; -} vr::EVRInitError LucidGloveDeviceDriver::Activate(uint32_t unObjectId) { - const bool isRightHand = IsRightHand(); + const bool isRightHand = IsRightHand(); - m_driverId = unObjectId; //unique ID for your driver - m_controllerPose = std::make_unique(m_configuration.role, std::string(lucidGlove::c_deviceManufacturer), m_configuration.poseConfiguration); + 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::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); - vr::VRProperties()->SetStringProperty(props, vr::Prop_InputProfilePath_String, lucidGlove::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()->SetStringProperty(props, vr::Prop_SerialNumber_String, GetSerialNumber().c_str()); - vr::VRProperties()->SetStringProperty(props, vr::Prop_ModelNumber_String, lucidGlove::c_deviceModelNumber); - vr::VRProperties()->SetStringProperty(props, vr::Prop_ManufacturerName_String, lucidGlove::c_deviceManufacturer); - vr::VRProperties()->SetInt32Property(props, vr::Prop_DeviceClass_Int32, (int32_t)vr::TrackedDeviceClass_Controller); - vr::VRProperties()->SetStringProperty(props, vr::Prop_ControllerType_String, lucidGlove::c_deviceControllerType); + vr::VRProperties()->SetInt32Property(props, vr::Prop_ControllerHandSelectionPriority_Int32, (int32_t)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()->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_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()->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, "/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()->CreateBooleanComponent(props, isRightHand ? "/input/A/click" : "/input/system/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_A]); - vr::VRDriverInput()->CreateBooleanComponent(props, "/input/B/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_B]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/B/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_B]); - 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, "/input/grab/click", &m_inputComponentHandles[ComponentIndex::COMP_GES_GRAB]); + vr::VRDriverInput()->CreateBooleanComponent(props, "/input/pinch/click", &m_inputComponentHandles[ComponentIndex::COMP_GES_PINCH]); - vr::VRDriverInput()->CreateHapticComponent(props, "output/haptic", &m_inputComponentHandles[ComponentIndex::COMP_HAPTIC]); + vr::VRDriverInput()->CreateHapticComponent(props, "output/haptic", &m_inputComponentHandles[ComponentIndex::COMP_HAPTIC]); - 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()->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); - // Create the skeletal component and save the handle for later use + // Create the skeletal component and save the handle for later use - 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); + 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); - } + if (error != vr::VRInputError_None) { + // Handle failure case + DebugDriverLog("CreateSkeletonComponent failed. Error: %s\n", error); + } - StartDevice(); + StartDevice(); - m_hasActivated = true; + m_hasActivated = true; - return vr::VRInitError_None; + return vr::VRInitError_None; } -//This could do with a rename, its a bit vague as to what it does +// This could do with a rename, its a bit vague as to what it does void LucidGloveDeviceDriver::StartDevice() { - m_communicationManager->Connect(); - //DebugDriverLog("Getting ready to connect:"); - if (m_communicationManager->IsConnected()) { - //DebugDriverLog("Connected successfully"); - m_communicationManager->BeginListener([&](VRCommData_t datas) { - try { - //Compute each finger transform - for (int i = 0; i < NUM_BONES; i++) { - int fingerNum = FingerFromBone(i); - if (fingerNum != -1) { - ComputeBoneFlexion(&m_handTransforms[i], datas.flexion[fingerNum], i, 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); - } - catch (const std::exception& e) { - DebugDriverLog("Exception caught while parsing comm data"); - } - }); - - } - else { - DebugDriverLog("Device did not connect successfully"); - //Perhaps retry - } + m_communicationManager->Connect(); + // DebugDriverLog("Getting ready to connect:"); + if (m_communicationManager->IsConnected()) { + // DebugDriverLog("Connected successfully"); + m_communicationManager->BeginListener([&](VRCommData_t datas) { + try { + // Compute each finger transform + for (int i = 0; i < NUM_BONES; i++) { + int fingerNum = FingerFromBone(i); + if (fingerNum != -1) { + ComputeBoneFlexion(&m_handTransforms[i], datas.flexion[fingerNum], i, 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); + + if (datas.calibrate) { + if (!m_controllerPose->isCalibrating()) m_controllerPose->StartCalibration(); + } else { + if (m_controllerPose->isCalibrating()) m_controllerPose->FinishCalibration(); + } + } catch (const std::exception& e) { + DebugDriverLog("Exception caught while parsing comm data"); + } + }); + + } else { + DebugDriverLog("Device did not connect successfully"); + } } vr::DriverPose_t LucidGloveDeviceDriver::GetPose() { - if (m_hasActivated) return m_controllerPose->UpdatePose(); + if (m_hasActivated) return m_controllerPose->UpdatePose(); - vr::DriverPose_t pose = { 0 }; - return pose; + 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)); - } + 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; - } + if (m_hasActivated) { + m_communicationManager->Disconnect(); + m_driverId = vr::k_unTrackedDeviceIndexInvalid; + } } -void* LucidGloveDeviceDriver::GetComponent(const char* pchComponentNameAndVersion) { - return nullptr; -} +void* LucidGloveDeviceDriver::GetComponent(const char* pchComponentNameAndVersion) { return nullptr; } void LucidGloveDeviceDriver::EnterStandby() {} void LucidGloveDeviceDriver::DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) { - if (unResponseBufferSize >= 1) { - pchResponseBuffer[0] = 0; - } + if (unResponseBufferSize >= 1) { + pchResponseBuffer[0] = 0; + } } \ No newline at end of file From e3fd882212b1d7495655073d2a1d8e2fb3004e52 Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Mon, 2 Aug 2021 13:10:42 -0400 Subject: [PATCH 23/27] Generalize BTSerial function signatures (#114) --- .../BTSerialCommunicationManager.h | 8 ++--- .../BTSerialCommunicationManager.cpp | 34 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/Communication/BTSerialCommunicationManager.h b/include/Communication/BTSerialCommunicationManager.h index 82960e61..e4256565 100644 --- a/include/Communication/BTSerialCommunicationManager.h +++ b/include/Communication/BTSerialCommunicationManager.h @@ -36,10 +36,10 @@ class BTSerialCommunicationManager : public ICommunicationManager { private: void ListenerThread(const std::function& callback); bool ReceiveNextPacket(std::string& buff); - bool getPairedEsp32BtAddress(); + bool getPairedDeviceBtAddress(); bool startupWindowsSocket(); - bool connectToEsp32(); - bool sendMessageToEsp32(); + bool connectToDevice(); + bool sendMessageToDevice(); bool m_isConnected; std::atomic m_threadActive; std::thread m_serialThread; @@ -48,7 +48,7 @@ class BTSerialCommunicationManager : public ICommunicationManager { VRBTSerialConfiguration_t m_btSerialConfiguration; - BTH_ADDR m_esp32BtAddress; + BTH_ADDR m_deviceBtAddress; SOCKADDR_BTH m_btSocketAddress; SOCKET m_btClientSocket; WCHAR* m_wcDeviceName; diff --git a/src/Communication/BTSerialCommunicationManager.cpp b/src/Communication/BTSerialCommunicationManager.cpp index 08999b81..5c90dfeb 100644 --- a/src/Communication/BTSerialCommunicationManager.cpp +++ b/src/Communication/BTSerialCommunicationManager.cpp @@ -12,7 +12,7 @@ void BTSerialCommunicationManager::Connect() { m_isConnected = false; // Try to connect - if (!getPairedEsp32BtAddress()) // find an ESP32 paired with this machine + if (!getPairedDeviceBtAddress()) // find an device paired with this machine { DriverLog("Error getting Bluetooth address"); return; @@ -22,7 +22,7 @@ void BTSerialCommunicationManager::Connect() { DriverLog("Error Initializing windows sockets"); return; } - if (!connectToEsp32()) // initialize BT windows socket for connecting to ESP32 + if (!connectToDevice()) // initialize BT windows socket for connecting to device { DriverLog("Error connecting to Bluetooth device"); return; @@ -50,7 +50,7 @@ void BTSerialCommunicationManager::ListenerThread(const std::functionDecode(receivedString); callback(commData); - sendMessageToEsp32(); + sendMessageToDevice(); } catch (const std::invalid_argument& ia) { DriverLog("Received error from encoding manager. Skipping..."); } @@ -97,7 +97,7 @@ void BTSerialCommunicationManager::Disconnect() { // Disconnect if (shutdown(m_btClientSocket, 2) == SOCKET_ERROR) { - DriverLog("Could not disconnect socket from ESP32. Error %ld", WSAGetLastError()); + DriverLog("Could not disconnect socket from bluetooth device. Error %ld", WSAGetLastError()); } else DriverLog("Disconnected from socket successfully."); } @@ -107,9 +107,9 @@ bool BTSerialCommunicationManager::IsConnected() { return m_isConnected; } /// /// Gets the bluetooth devices paired with this machine and -/// finds an ESP32. If it finds one, its BT address is stored. +/// finds a device. If it finds one, its BT address is stored. /// -bool BTSerialCommunicationManager::getPairedEsp32BtAddress() { +bool BTSerialCommunicationManager::getPairedDeviceBtAddress() { BLUETOOTH_DEVICE_SEARCH_PARAMS btDeviceSearchParameters = { sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), // size of object 1, // return authenticated devices @@ -132,19 +132,19 @@ bool BTSerialCommunicationManager::getPairedEsp32BtAddress() { m_wcDeviceName = (WCHAR*)(thiswstring.c_str()); if (wcscmp(btDeviceInfo.szName, m_wcDeviceName) == 0) { // - DriverLog("ESP32 found!\r\n"); + DriverLog("Bluetooth Device found!\r\n"); if (btDeviceInfo.fAuthenticated) // I found that if fAuthenticated is true it means the device is paired. { - DriverLog("ESP32 is authenticated.\r\n"); - m_esp32BtAddress = btDeviceInfo.Address.ullLong; + DriverLog("Bluetooth Device is authenticated.\r\n"); + m_deviceBtAddress = btDeviceInfo.Address.ullLong; return true; } else { - DriverLog("This ESP32 is not authenticated. Please pair with it first.\r\n"); + DriverLog("This Bluetooth Device is not authenticated. Please pair with it first.\r\n"); } } } while (BluetoothFindNextDevice(btDevice, &btDeviceInfo)); // loop through remaining BT devices connected to this machine - DriverLog("Could not find a paired ESP32 with name %s", m_btSerialConfiguration.name.c_str()); + DriverLog("Could not find a paired Bluetooth Device with name %s", m_btSerialConfiguration.name.c_str()); return false; } @@ -160,16 +160,16 @@ bool BTSerialCommunicationManager::startupWindowsSocket() { return true; } -bool BTSerialCommunicationManager::connectToEsp32() { +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_esp32BtAddress; // this is the BT address of the remote device. + 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. { - DriverLog("Could not connect socket to ESP32. Error %ld", WSAGetLastError()); + DriverLog("Could not connect socket to Bluetooth Device. Error %ld", WSAGetLastError()); return false; } unsigned long nonBlockingMode = 1; @@ -181,13 +181,13 @@ bool BTSerialCommunicationManager::connectToEsp32() { return true; } -bool BTSerialCommunicationManager::sendMessageToEsp32() { +bool BTSerialCommunicationManager::sendMessageToDevice() { std::lock_guard lock(m_writeMutex); const char* message = m_writeString.c_str(); - //DebugDriverLog("Sending %s to ESP32.", m_writeString.c_str()); + //DebugDriverLog("Sending %s to Bluetooth Device.", 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) { - DriverLog("Sending to ESP32 failed. Error code %d", WSAGetLastError()); + DriverLog("Sending to Bluetooth Device failed. Error code %d", WSAGetLastError()); closesocket(m_btClientSocket); WSACleanup(); return false; From bd9e2852c848f48bcdd0b1704abe0da9327c7eae Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:42:41 -0400 Subject: [PATCH 24/27] Menu button (#115) * Add menu button to VRCommData_t * Add menu button to lucid glove driver * Add menu button to knuckle driver * Change menu button input mapping for lucid glove driver * Remove debug --- include/DeviceDriver/LucidGloveDriver.h | 2 +- include/Encode/EncodingManager.h | 5 ++++- libraries/asio | 1 + openglove/resources/input/openglove_profile.json | 12 +++++++----- src/DeviceDriver/KnuckleDriver.cpp | 3 +++ src/DeviceDriver/LucidGloveDriver.cpp | 11 ++++++++--- src/Encode/AlphaEncodingManager.cpp | 3 ++- src/Encode/LegacyEncodingManager.cpp | 1 + 8 files changed, 27 insertions(+), 11 deletions(-) create mode 160000 libraries/asio diff --git a/include/DeviceDriver/LucidGloveDriver.h b/include/DeviceDriver/LucidGloveDriver.h index 73d74978..d9b4f6fa 100644 --- a/include/DeviceDriver/LucidGloveDriver.h +++ b/include/DeviceDriver/LucidGloveDriver.h @@ -46,7 +46,7 @@ class LucidGloveDeviceDriver : public IDeviceDriver { uint32_t m_driverId; vr::VRInputComponentHandle_t m_skeletalComponentHandle{}; - vr::VRInputComponentHandle_t m_inputComponentHandles[14]{}; + vr::VRInputComponentHandle_t m_inputComponentHandles[15]{}; vr::VRBoneTransform_t m_handTransforms[NUM_BONES]; diff --git a/include/Encode/EncodingManager.h b/include/Encode/EncodingManager.h index 0dbb82cd..ea6d6778 100644 --- a/include/Encode/EncodingManager.h +++ b/include/Encode/EncodingManager.h @@ -4,7 +4,7 @@ #include "ForceFeedback.h" struct VRCommData_t { - VRCommData_t(std::array flexion, std::array splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool calibrate) : + VRCommData_t(std::array flexion, std::array splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool menu, bool calibrate) : flexion(flexion), splay(splay), joyX(joyX), @@ -15,8 +15,10 @@ struct VRCommData_t { bButton(bButton), grab(grab), pinch(pinch), + menu(menu), calibrate(calibrate){}; + std::array flexion; std::array splay; float joyX; @@ -27,6 +29,7 @@ struct VRCommData_t { bool bButton; bool grab; bool pinch; + bool menu; bool calibrate; }; diff --git a/libraries/asio b/libraries/asio new file mode 160000 index 00000000..57577c6d --- /dev/null +++ b/libraries/asio @@ -0,0 +1 @@ +Subproject commit 57577c6db46a4e2de5351af2b185bf52696699a9 diff --git a/openglove/resources/input/openglove_profile.json b/openglove/resources/input/openglove_profile.json index caa3b78e..4aa2a615 100644 --- a/openglove/resources/input/openglove_profile.json +++ b/openglove/resources/input/openglove_profile.json @@ -40,11 +40,6 @@ "binding_image_point": [ 11, 60 ], "order": 2 }, - "/input/system/click": { - "type": "button", - "binding_image_point": [ 67, 81 ], - "order": 3 - }, "/input/A/click": { "type": "button", "binding_image_point": [ 67, 81 ], @@ -94,6 +89,13 @@ "type": "trigger", "visibility": "InputValueVisibility_AvailableButHidden", "binding_image_point": [ 56, 86 ] + }, + "/input/system" : { + "type" : "button", + "click" : true, + "touch" : true, + "binding_image_point" : [ 34,45 ], + "order" : 1 } } } \ No newline at end of file diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp index 6b8f38c9..f3cda1bf 100644 --- a/src/DeviceDriver/KnuckleDriver.cpp +++ b/src/DeviceDriver/KnuckleDriver.cpp @@ -223,6 +223,9 @@ void KnuckleDeviceDriver::StartDevice() { 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); diff --git a/src/DeviceDriver/LucidGloveDriver.cpp b/src/DeviceDriver/LucidGloveDriver.cpp index 5db623bb..75aa050b 100644 --- a/src/DeviceDriver/LucidGloveDriver.cpp +++ b/src/DeviceDriver/LucidGloveDriver.cpp @@ -22,7 +22,8 @@ enum ComponentIndex : int { COMP_TRG_INDEX = 10, COMP_TRG_MIDDLE = 11, COMP_TRG_RING = 12, - COMP_TRG_PINKY = 13 + COMP_TRG_PINKY = 13, + COMP_BTN_MENU = 14, }; LucidGloveDeviceDriver::LucidGloveDeviceDriver(VRDeviceConfiguration_t configuration, std::unique_ptr communicationManager, @@ -84,8 +85,11 @@ vr::EVRInitError LucidGloveDeviceDriver::Activate(uint32_t unObjectId) { 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/system/click", &m_inputComponentHandles[ComponentIndex::COMP_BTN_MENU]); - // Create the skeletal component and save the handle for later use + + // Create the skeletal component and save the handle for later use// vr::EVRInputError error = vr::VRDriverInput()->CreateSkeletonComponent( props, isRightHand ? "/input/skeleton/right" : "/input/skeleton/left", isRightHand ? "/skeleton/hand/right" : "/skeleton/hand/left", "/pose/raw", @@ -137,7 +141,8 @@ void LucidGloveDeviceDriver::StartDevice() { 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 { diff --git a/src/Encode/AlphaEncodingManager.cpp b/src/Encode/AlphaEncodingManager.cpp index 7258032c..fa6c81f7 100644 --- a/src/Encode/AlphaEncodingManager.cpp +++ b/src/Encode/AlphaEncodingManager.cpp @@ -79,7 +79,8 @@ VRCommData_t AlphaEncodingManager::Decode(std::string input) { argValid(input, 'K'), //B button argValid(input, 'L'), //grab argValid(input, 'M'), //pinch - argValid(input, 'O') //calibration (N reserved for menu btn) + argValid(input, 'N'), //menu + argValid(input, 'O') //calibration ); return commData; diff --git a/src/Encode/LegacyEncodingManager.cpp b/src/Encode/LegacyEncodingManager.cpp index 86d02840..17264b00 100644 --- a/src/Encode/LegacyEncodingManager.cpp +++ b/src/Encode/LegacyEncodingManager.cpp @@ -40,6 +40,7 @@ VRCommData_t LegacyEncodingManager::Decode(std::string input) { tokens[VRCommDataInputPosition::BTN_B] == 1, tokens[VRCommDataInputPosition::GES_GRAB] == 1, tokens[VRCommDataInputPosition::GES_PINCH] == 1, + false, false ); From 57bdf17be5db2477b55f353f7dddf970ea662dcc Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Tue, 3 Aug 2021 20:28:10 +0100 Subject: [PATCH 25/27] potential named pipe crash fix (#116) --- src/ControllerDiscovery.cpp | 3 +-- src/ForceFeedback.cpp | 3 +-- src/Util/NamedPipe.cpp | 4 +++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ControllerDiscovery.cpp b/src/ControllerDiscovery.cpp index 3e8f76cc..0a7d7ae5 100644 --- a/src/ControllerDiscovery.cpp +++ b/src/ControllerDiscovery.cpp @@ -14,8 +14,7 @@ void ControllerDiscovery::Start() { m_pipe->Start([&](LPVOID data) { ControllerDiscoveryPipeData_t *controllerPipeData = (ControllerDiscoveryPipeData_t *)data; - ControllerDiscoveryPipeData_t result(*controllerPipeData); - m_callback(result); + m_callback(*controllerPipeData); }); }; diff --git a/src/ForceFeedback.cpp b/src/ForceFeedback.cpp index ffd2a5bc..34ff151a 100644 --- a/src/ForceFeedback.cpp +++ b/src/ForceFeedback.cpp @@ -14,8 +14,7 @@ void FFBListener::Start() { m_pipe->Start([&](LPVOID data) { VRFFBData_t *ffbData = (VRFFBData_t *)data; - VRFFBData_t result(*ffbData); - m_callback(result); + m_callback(*ffbData); }); } diff --git a/src/Util/NamedPipe.cpp b/src/Util/NamedPipe.cpp index 28c1b76a..904efdc8 100644 --- a/src/Util/NamedPipe.cpp +++ b/src/Util/NamedPipe.cpp @@ -152,7 +152,9 @@ void NamedPipeUtil::PipeListenerThread(const std::function &callba } break; } - + case WAIT_IO_COMPLETION: { + break; + } default: { DriverLog("WaitForSingleObjectEx with error: %s.\n", GetLastErrorAsString().c_str()); return; From 8c857dd1e54e363c12a4dec1c3661ebc88a0536b Mon Sep 17 00:00:00 2001 From: danwillm <39023874+danwillm@users.noreply.github.com> Date: Wed, 4 Aug 2021 21:18:06 +0100 Subject: [PATCH 26/27] Close and reopen named pipe fix (#117) * potential named pipe crash fix * fix for disconnecting and reconnecting to named pipe not working --- include/Util/NamedPipe.h | 2 +- src/Util/NamedPipe.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/Util/NamedPipe.h b/include/Util/NamedPipe.h index 750a3d5a..672ee8aa 100644 --- a/include/Util/NamedPipe.h +++ b/include/Util/NamedPipe.h @@ -23,7 +23,7 @@ class NamedPipeUtil { private: void PipeListenerThread(const std::function& callback); - void DisconnectAndClose(); + void ClosePipe(); bool CreateAndConnectInstance(LPOVERLAPPED lpo, std::string& pipeName); bool ConnectToNewClient(LPOVERLAPPED lpo); diff --git a/src/Util/NamedPipe.cpp b/src/Util/NamedPipe.cpp index 904efdc8..52a42baa 100644 --- a/src/Util/NamedPipe.cpp +++ b/src/Util/NamedPipe.cpp @@ -107,6 +107,7 @@ void NamedPipeUtil::PipeListenerThread(const std::function &callba return; } + oConnect.hEvent = hConnectEvent; DriverLog("Creating pipe: %s", m_pipeName.c_str()); fPendingIO = CreateAndConnectInstance(&oConnect, m_pipeName); @@ -127,6 +128,7 @@ void NamedPipeUtil::PipeListenerThread(const std::function &callba return; } } + m_lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST)); if (m_lpPipeInst == NULL) { @@ -146,7 +148,7 @@ void NamedPipeUtil::PipeListenerThread(const std::function &callba switch (GetLastError()) { case ERROR_BROKEN_PIPE: DriverLog("Detected that a client disconnected for pipe: %s", m_pipeName.c_str()); - DisconnectAndClose(); + ClosePipe(); PipeListenerThread(callback); break; } @@ -164,10 +166,8 @@ void NamedPipeUtil::PipeListenerThread(const std::function &callba } } -void NamedPipeUtil::DisconnectAndClose() { +void NamedPipeUtil::ClosePipe() { DriverLog("Closing pipe: %s", m_pipeName.c_str()); - if (m_listenerActive) m_listenerActive = false; - if (!DisconnectNamedPipe(m_lpPipeInst->hPipeInst)) { DriverLog("DisconnectNamedPipe failed with error: %s.\n", GetLastErrorAsString().c_str()); } @@ -179,9 +179,11 @@ void NamedPipeUtil::DisconnectAndClose() { } void NamedPipeUtil::Stop() { - m_listenerActive = false; - m_pipeThread.join(); - DisconnectAndClose(); + if (m_listenerActive) { + m_listenerActive = false; + m_pipeThread.join(); + ClosePipe(); + } } NamedPipeUtil::~NamedPipeUtil() { Stop(); }; \ No newline at end of file From 8de56c0a885a895a914af4b9de64a5dc3085bf4d Mon Sep 17 00:00:00 2001 From: Lucas LucidVR <35583218+lucas-vrtech@users.noreply.github.com> Date: Sat, 7 Aug 2021 13:16:33 -0400 Subject: [PATCH 27/27] Readme features update v0.4 (#109) * Update README.md * Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8be222ec..1b2fc51e 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,11 @@ If you are planning on modifying source files, refer to [BUILDING.md](https://gi ### Current features included in the driver * Finger flexion tracking +* Force feedback haptics * Positioning from controllers + trackers + * Automatic Calibration * Button/Joystick inputs + * A/B/Menu buttons, Joystick X/Y/Click * Communication Protocols: * Serial USB * Serial over Bluetooth @@ -44,7 +47,6 @@ If you are planning on modifying source files, refer to [BUILDING.md](https://gi ### Planned features * BLE Communication * Finger splay tracking -* Force feedback haptics * Vibration haptics