From 376eac311b8ff763818dc7f445d0e11c6c8415f8 Mon Sep 17 00:00:00 2001 From: quebec Date: Thu, 12 May 2016 10:57:04 +0200 Subject: [PATCH] ADDED: Tracked Controller support. --- README.md | 15 + src/CMakeLists.txt | 5 +- src/OSVRTrackedDeviceController.cpp | 794 ++++++++++++++++++++++++++++ src/OSVRTrackedDeviceController.h | 205 +++++++ src/ServerDriver_OSVR.cpp | 48 +- src/ServerDriver_OSVR.h | 2 + 6 files changed, 1052 insertions(+), 17 deletions(-) create mode 100644 src/OSVRTrackedDeviceController.cpp create mode 100644 src/OSVRTrackedDeviceController.h diff --git a/README.md b/README.md index d3b576a..cdf6633 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,18 @@ +## Introduction +This is a fork of the original SteamVR driver for OSVR. It is just an extension of the original driver for supporting the Hand-Controllers. + +I don't have the time to continue this for the moment. + +## Known Problems +1. You can use it together with the Rift, but you need to activate multidriver support in SteamVR (there is a tutorial on this for the Hydra SteamVR drivers). +2. The second hand controller is detected but the data is not send to SteamVR (the code is there, seems to be a bug) +3. The touchpad is not implemented. (Most should work with the joysticks, so touchpad was not needed so far.) +4. Left FGamepadKeyNames::MotionController_Left_Thumbstick(name from UE4 OSVR plugin) is not mapped to /controller/left/joystick/button (same for right one). But you can it as buttons mapped to e.g. /controller/left/5 . +5. Same for FGamepadKeyNames::MotionController_Left_Shoulder(name from UE4 OSVR plugin) mapped to /controller/left/bumper +6. And FGamepadKeyNames::SpecialLeft(name from UE4 OSVR plugin) /controller/left/middle + +Here is the original text: + # SteamVR Driver Using OSVR [![Join the chat at https://gitter.im/OSVR/SteamVR-OSVR](https://badges.gitter.im/OSVR/SteamVR-OSVR.svg)](https://gitter.im/OSVR/SteamVR-OSVR?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 85fcf60..bd5923f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,4 @@ +cmake_minimum_required(VERSION 3.1) # # OpenVR OSVR driver # @@ -38,6 +39,8 @@ add_library(driver_osvr osvr_dll_export.h OSVRTrackedDevice.cpp OSVRTrackedDevice.h + OSVRTrackedDeviceController.cpp + OSVRTrackedDeviceController.h platform_fixes.h ServerDriver_OSVR.cpp ServerDriver_OSVR.h @@ -58,7 +61,7 @@ install(TARGETS driver_osvr DESTINATION "drivers/osvr/bin/${OPENVR_PLATFORM}") if(WIN32) - include(CopyImportedTarget) + include(../cmake/CopyImportedTarget.cmake) foreach(target osvr::osvrClientKit osvr::osvrClient osvr::osvrCommon osvr::osvrUtil) copy_imported_targets(${target}) # for use in build tree install_imported_target(${target} DESTINATION "drivers/osvr/bin/${OPENVR_PLATFORM}") # in installed directory diff --git a/src/OSVRTrackedDeviceController.cpp b/src/OSVRTrackedDeviceController.cpp new file mode 100644 index 0000000..8b13477 --- /dev/null +++ b/src/OSVRTrackedDeviceController.cpp @@ -0,0 +1,794 @@ +/** @file +@brief OSVR tracked device + +@date 2015 + +@author +Sensics, Inc. + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Internal Includes +#include "OSVRTrackedDeviceController.h" + +#include "osvr_compiler_detection.h" +#include "make_unique.h" +#include "matrix_cast.h" +#include "osvr_device_properties.h" +#include "ValveStrCpy.h" +#include "platform_fixes.h" // strcasecmp + +// OpenVR includes +#include + +// Library/third-party includes +#include +#include +#include +#include + +// Standard includes +#include +#include +#include +#include +#include + +// TODO: +// Trackpad +// OSVRButton(OSVR_BUTTON_TYPE_DIGITAL, FGamepadKeyNames::MotionController_Left_Thumbstick, "/controller/left/joystick/button"), +// OSVRButton(OSVR_BUTTON_TYPE_DIGITAL, FGamepadKeyNames::MotionController_Left_Shoulder, "/controller/left/bumper"), +// OSVRButton(OSVR_BUTTON_TYPE_DIGITAL, FGamepadKeyNames::SpecialLeft, "/controller/left/middle"), + +OSVRTrackedDeviceController::OSVRTrackedDeviceController(int controllerIndex, osvr::clientkit::ClientContext& context, vr::IServerDriverHost* driver_host, vr::IDriverLog* driver_log) + : m_ControllerIndex(controllerIndex), m_Context(context), driver_host_(driver_host), logger_(driver_log), pose_(), deviceClass_(vr::TrackedDeviceClass_Controller) +{ + m_ControllerName = "OSVRController" + std::to_string(controllerIndex); + + m_NumAxis = 0; + for (int iter_axis = 0; iter_axis < NUM_AXIS; iter_axis++) + { + m_AnalogInterface[iter_axis].parentController = this; + m_AnalogInterface[iter_axis].axisType = vr::EVRControllerAxisType::k_eControllerAxis_None; + } +} + +OSVRTrackedDeviceController::~OSVRTrackedDeviceController() +{ + vr::IDriverLog* logger_ = nullptr; + vr::IServerDriverHost* driver_host_ = nullptr; +} + +vr::EVRInitError OSVRTrackedDeviceController::Activate(uint32_t object_id) +{ + const std::time_t waitTime = 5; // wait up to 5 seconds for init + + FreeInterfaces(); + m_NumAxis = 0; + + // Ensure context is fully started up + logger_->Log("Waiting for the context to fully start up...\n"); + std::time_t startTime = std::time(nullptr); + while (!m_Context.checkStatus()) { + m_Context.update(); + if (std::time(nullptr) > startTime + waitTime) { + logger_->Log("Context startup timed out!\n"); + return vr::VRInitError_Driver_Failed; + } + } + + // Register callbacks + std::string trackerPath; + std::string buttonPath; + std::string triggerPath; + std::string joystickPath; + if (m_ControllerIndex == 0) + { + trackerPath = "/me/hands/left"; + buttonPath = "/controller/left/"; + triggerPath = "/controller/left/trigger"; + joystickPath = "/controller/left/joystick"; + } + else if (m_ControllerIndex == 1) + { + trackerPath = "/me/hands/right"; + buttonPath = "/controller/right/"; + triggerPath = "/controller/right/trigger"; + joystickPath = "/controller/right/joystick"; + } + else + { + buttonPath = "/controller" + std::to_string(m_ControllerIndex) + "/"; + triggerPath = "/controller" + std::to_string(m_ControllerIndex) + "/trigger"; + joystickPath = "/controller" + std::to_string(m_ControllerIndex) + "/joystick"; + } + + if (!trackerPath.empty()) + { + m_TrackerInterface = m_Context.getInterface(trackerPath); + m_TrackerInterface.registerCallback(&OSVRTrackedDeviceController::ControllerTrackerCallback, this); + } + + for (int iter_button = 0; iter_button < NUM_BUTTONS; iter_button++) + { + m_ButtonInterface[iter_button] = m_Context.getInterface(buttonPath + std::to_string(iter_button)); + if (m_ButtonInterface[iter_button].notEmpty()) + m_ButtonInterface[iter_button].registerCallback(&OSVRTrackedDeviceController::ControllerButtonCallback, this); + else + m_ButtonInterface[iter_button].free(); + } + + // TODO: ADD TOUCHPAD PART HERE + m_NumAxis = 0; + + m_NumAxis = 1; + for (int iter_trigger = 0; iter_trigger < NUM_TRIGGER; iter_trigger++) + { + if (m_NumAxis >= NUM_AXIS) + break; + + if (iter_trigger == 0) + m_AnalogInterface[m_NumAxis].analogInterfaceX = m_Context.getInterface(triggerPath); + else + m_AnalogInterface[m_NumAxis].analogInterfaceX = m_Context.getInterface(triggerPath + std::to_string(iter_trigger)); + + if (m_AnalogInterface[m_NumAxis].analogInterfaceX.notEmpty()) + { + m_AnalogInterface[m_NumAxis].axisIndex = m_NumAxis; + m_AnalogInterface[m_NumAxis].axisType = vr::EVRControllerAxisType::k_eControllerAxis_Trigger; + m_AnalogInterface[m_NumAxis].analogInterfaceX.registerCallback(&OSVRTrackedDeviceController::ControllerTriggerCallback, &m_AnalogInterface[m_NumAxis]); + m_NumAxis++; + } + else + m_AnalogInterface[m_NumAxis].analogInterfaceX.free(); + } + + m_NumAxis = 2; + for (int iter_joystick = 0; iter_joystick < NUM_JOYSTICKS; iter_joystick++) + { + if (m_NumAxis >= NUM_AXIS) + break; + + if (iter_joystick == 0) + { + m_AnalogInterface[m_NumAxis].analogInterfaceX = m_Context.getInterface(joystickPath + "/x"); + m_AnalogInterface[m_NumAxis].analogInterfaceY = m_Context.getInterface(joystickPath + "/y"); + } + else + { + m_AnalogInterface[m_NumAxis].analogInterfaceX = m_Context.getInterface(joystickPath + std::to_string(iter_joystick) + "/x"); + m_AnalogInterface[m_NumAxis].analogInterfaceY = m_Context.getInterface(joystickPath + std::to_string(iter_joystick) + "/y"); + } + + bool somethingFound = false; + + if (m_AnalogInterface[m_NumAxis].analogInterfaceX.notEmpty()) + { + m_AnalogInterface[m_NumAxis].axisIndex = m_NumAxis; + m_AnalogInterface[m_NumAxis].axisType = vr::EVRControllerAxisType::k_eControllerAxis_Joystick; + m_AnalogInterface[m_NumAxis].analogInterfaceX.registerCallback(&OSVRTrackedDeviceController::ControllerJoystickXCallback, &m_AnalogInterface[m_NumAxis]); + somethingFound = true; + } + else + { + m_AnalogInterface[m_NumAxis].analogInterfaceX.free(); + } + + if (m_AnalogInterface[m_NumAxis].analogInterfaceY.notEmpty()) + { + m_AnalogInterface[m_NumAxis].axisIndex = m_NumAxis; + m_AnalogInterface[m_NumAxis].axisType = vr::EVRControllerAxisType::k_eControllerAxis_Joystick; + m_AnalogInterface[m_NumAxis].analogInterfaceY.registerCallback(&OSVRTrackedDeviceController::ControllerJoystickYCallback, &m_AnalogInterface[m_NumAxis]); + somethingFound = true; + } + else + { + m_AnalogInterface[m_NumAxis].analogInterfaceY.free(); + } + + if (somethingFound) + m_NumAxis++; + } + + return vr::VRInitError_None; +} + +void OSVRTrackedDeviceController::Deactivate() +{ + /// Have to force freeing here + FreeInterfaces(); +} + +void OSVRTrackedDeviceController::PowerOff() +{ + // FIXME Implement +} + +void* OSVRTrackedDeviceController::GetComponent(const char* component_name_and_version) +{ + if (!strcasecmp(component_name_and_version, vr::IVRControllerComponent_Version)) { + return (vr::IVRControllerComponent*)this; + } + + // Override this to add a component to a driver + return NULL; +} + +void OSVRTrackedDeviceController::DebugRequest(const char* request, char* response_buffer, uint32_t response_buffer_size) +{ + // TODO + // make use of (from vrtypes.h) static const uint32_t k_unMaxDriverDebugResponseSize = 32768; +} + +/** Gets the current state of a controller. */ +vr::VRControllerState_t OSVRTrackedDeviceController::GetControllerState() +{ + //logger_->Log("ControllerState requested"); + vr::VRControllerState_t state; + state.unPacketNum = 0; + return state; +} + +/** Returns a uint64 property. If the property is not available this function will return 0. */ +bool OSVRTrackedDeviceController::TriggerHapticPulse(uint32_t unAxisId, uint16_t usPulseDurationMicroseconds) +{ + return 0; +} + +vr::DriverPose_t OSVRTrackedDeviceController::GetPose() +{ + return pose_; +} + +bool OSVRTrackedDeviceController::GetBoolTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) +{ + const bool default_value = false; + + if (isWrongDataType(prop, bool())) { + if (error) + *error = vr::TrackedProp_WrongDataType; + return default_value; + } + + if (isWrongDeviceClass(prop, deviceClass_)) { + if (error) + *error = vr::TrackedProp_WrongDeviceClass; + return default_value; + } + + if (vr::TrackedDeviceClass_Invalid == deviceClass_) { + if (error) + *error = vr::TrackedProp_InvalidDevice; + return default_value; + } + +#include "ignore-warning/push" +#include "ignore-warning/switch-enum" + + switch (prop) { + case vr::Prop_WillDriftInYaw_Bool: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + break; + case vr::Prop_ContainsProximitySensor_Bool: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + break; + } + +#include "ignore-warning/pop" + + if (error) + *error = vr::TrackedProp_UnknownProperty; + return default_value; +} + +float OSVRTrackedDeviceController::GetFloatTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) +{ + const float default_value = 0.0f; + + if (isWrongDataType(prop, float())) { + if (error) + *error = vr::TrackedProp_WrongDataType; + return default_value; + } + + if (isWrongDeviceClass(prop, deviceClass_)) { + if (error) + *error = vr::TrackedProp_WrongDeviceClass; + return default_value; + } + + if (vr::TrackedDeviceClass_Invalid == deviceClass_) { + if (error) + *error = vr::TrackedProp_InvalidDevice; + return default_value; + } + +#include "ignore-warning/push" +#include "ignore-warning/switch-enum" + + switch (prop) { + case vr::Prop_FieldOfViewLeftDegrees_Float: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_FieldOfViewRightDegrees_Float: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_FieldOfViewTopDegrees_Float: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_FieldOfViewBottomDegrees_Float: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_TrackingRangeMinimumMeters_Float: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_TrackingRangeMaximumMeters_Float: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + } + +#include "ignore-warning/pop" + + if (error) + *error = vr::TrackedProp_UnknownProperty; + return default_value; +} + +int32_t OSVRTrackedDeviceController::GetInt32TrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) +{ + const int32_t default_value = 0; + + if (isWrongDataType(prop, int32_t())) { + if (error) + *error = vr::TrackedProp_WrongDataType; + return default_value; + } + + if (isWrongDeviceClass(prop, deviceClass_)) { + if (error) + *error = vr::TrackedProp_WrongDeviceClass; + return default_value; + } + + if (vr::TrackedDeviceClass_Invalid == deviceClass_) { + if (error) + *error = vr::TrackedProp_InvalidDevice; + return default_value; + } + +#include "ignore-warning/push" +#include "ignore-warning/switch-enum" + + switch (prop) { + case vr::Prop_DeviceClass_Int32: + if (error) + *error = vr::TrackedProp_Success; + return deviceClass_; + case vr::Prop_Axis0Type_Int32: + //if (m_NumAxis > 0) + //{ + if (error) + *error = vr::TrackedProp_Success; + return m_AnalogInterface[0].axisType; + //} + //else + //{ + // if (error) + // *error = vr::TrackedProp_ValueNotProvidedByDevice; + // return default_value; + //} + case vr::Prop_Axis1Type_Int32: + //if (m_NumAxis > 1) + //{ + if (error) + *error = vr::TrackedProp_Success; + return m_AnalogInterface[1].axisType; + //} + //else + //{ + // if (error) + // *error = vr::TrackedProp_ValueNotProvidedByDevice; + // return default_value; + //} + case vr::Prop_Axis2Type_Int32: + //if (m_NumAxis > 2) + //{ + if (error) + *error = vr::TrackedProp_Success; + return m_AnalogInterface[2].axisType; + //} + //else + //{ + // if (error) + // *error = vr::TrackedProp_ValueNotProvidedByDevice; + // return default_value; + //} + case vr::Prop_Axis3Type_Int32: + //if (m_NumAxis > 3) + //{ + if (error) + *error = vr::TrackedProp_Success; + return m_AnalogInterface[3].axisType; + //} + //else + //{ + // if (error) + // *error = vr::TrackedProp_ValueNotProvidedByDevice; + // return default_value; + //} + case vr::Prop_Axis4Type_Int32: + //if (m_NumAxis > 4) + //{ + if (error) + *error = vr::TrackedProp_Success; + return m_AnalogInterface[4].axisType; + //} + //else + //{ + // if (error) + // *error = vr::TrackedProp_ValueNotProvidedByDevice; + // return default_value; + //} + } + +#include "ignore-warning/pop" + + if (error) + *error = vr::TrackedProp_UnknownProperty; + return default_value; +} + +uint64_t OSVRTrackedDeviceController::GetUint64TrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) +{ + const uint64_t default_value = 0; + + if (isWrongDataType(prop, uint64_t())) { + if (error) + *error = vr::TrackedProp_WrongDataType; + return default_value; + } + + if (isWrongDeviceClass(prop, deviceClass_)) { + if (error) + *error = vr::TrackedProp_WrongDeviceClass; + return default_value; + } + + if (vr::TrackedDeviceClass_Invalid == deviceClass_) { + if (error) + *error = vr::TrackedProp_InvalidDevice; + return default_value; + } + +#include "ignore-warning/push" +#include "ignore-warning/switch-enum" + + switch (prop) { + case vr::Prop_SupportedButtons_Uint64: // TODO + if (error) + *error = vr::TrackedProp_Success; + return NUM_BUTTONS; + } + +#include "ignore-warning/pop" + + if (error) + *error = vr::TrackedProp_UnknownProperty; + return default_value; +} + +vr::HmdMatrix34_t OSVRTrackedDeviceController::GetMatrix34TrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) +{ + // Default value is identity matrix + vr::HmdMatrix34_t default_value; + map(default_value) = Matrix34f::Identity(); + + if (isWrongDataType(prop, vr::HmdMatrix34_t())) { + if (error) + *error = vr::TrackedProp_WrongDataType; + return default_value; + } + + if (isWrongDeviceClass(prop, deviceClass_)) { + if (error) + *error = vr::TrackedProp_WrongDeviceClass; + return default_value; + } + + if (vr::TrackedDeviceClass_Invalid == deviceClass_) { + if (error) + *error = vr::TrackedProp_InvalidDevice; + return default_value; + } + +#include "ignore-warning/push" +#include "ignore-warning/switch-enum" + + switch (prop) { + case vr::Prop_StatusDisplayTransform_Matrix34: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + } + +#include "ignore-warning/pop" + + if (error) + *error = vr::TrackedProp_UnknownProperty; + return default_value; +} + +uint32_t OSVRTrackedDeviceController::GetStringTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, char *pchValue, uint32_t unBufferSize, vr::ETrackedPropertyError *pError) +{ + uint32_t default_value = 0; + if (isWrongDataType(prop, pchValue)) { + if (pError) + *pError = vr::TrackedProp_WrongDataType; + return default_value; + } + + if (isWrongDeviceClass(prop, deviceClass_)) { + if (pError) + *pError = vr::TrackedProp_WrongDeviceClass; + return default_value; + } + + if (vr::TrackedDeviceClass_Invalid == deviceClass_) { + if (pError) + *pError = vr::TrackedProp_InvalidDevice; + return default_value; + } + + std::string sValue = GetStringTrackedDeviceProperty(prop, pError); + if (*pError == vr::TrackedProp_Success) { + if (sValue.size() + 1 > unBufferSize) { + *pError = vr::TrackedProp_BufferTooSmall; + } + else { + valveStrCpy(sValue, pchValue, unBufferSize); + } + return static_cast(sValue.size()) + 1; + } + + return 0; +} + +// ------------------------------------ +// Private Methods +// ------------------------------------ + +void OSVRTrackedDeviceController::FreeInterfaces() +{ + if (m_TrackerInterface.notEmpty()) { + m_TrackerInterface.free(); + } + + for (int iter_axis = 0; iter_axis < NUM_AXIS; iter_axis++) + { + if (m_AnalogInterface[iter_axis].analogInterfaceX.notEmpty()) + m_AnalogInterface[iter_axis].analogInterfaceX.free(); + if (m_AnalogInterface[iter_axis].analogInterfaceY.notEmpty()) + m_AnalogInterface[iter_axis].analogInterfaceY.free(); + } + + for (int iter_button = 0; iter_button < NUM_BUTTONS; iter_button++) + { + if (m_ButtonInterface[iter_button].notEmpty()) + m_ButtonInterface[iter_button].free(); + } +} + +std::string OSVRTrackedDeviceController::GetStringTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *error) +{ + std::string default_value = ""; + +#include "ignore-warning/push" +#include "ignore-warning/switch-enum" + + switch (prop) { + case vr::Prop_TrackingSystemName_String: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_ModelNumber_String: // TODO + if (error) + *error = vr::TrackedProp_Success; + return "OSVR Controller"; + case vr::Prop_SerialNumber_String: + if (error) + *error = vr::TrackedProp_Success; + return m_ControllerName.c_str(); + case vr::Prop_RenderModelName_String: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_ManufacturerName_String: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_TrackingFirmwareVersion_String: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_HardwareRevision_String: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_AttachedDeviceId_String: // TODO + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_AllWirelessDongleDescriptions_String: + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + case vr::Prop_ConnectedWirelessDongle_String: + if (error) + *error = vr::TrackedProp_ValueNotProvidedByDevice; + return default_value; + } + +#include "ignore-warning/pop" + + if (error) + *error = vr::TrackedProp_UnknownProperty; + return default_value; +} + +inline vr::HmdQuaternion_t HmdQuaternion_Init(double w, double x, double y, double z) +{ + vr::HmdQuaternion_t quat; + quat.w = w; + quat.x = x; + quat.y = y; + quat.z = z; + return quat; +} + +void OSVRTrackedDeviceController::ControllerTrackerCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_PoseReport* report) +{ + if (!userdata) + return; + + auto* self = static_cast(userdata); + + vr::DriverPose_t pose = { 0 }; + pose.poseTimeOffset = 0; // close enough + + Eigen::Vector3d::Map(pose.vecWorldFromDriverTranslation) = Eigen::Vector3d::Zero(); + Eigen::Vector3d::Map(pose.vecDriverFromHeadTranslation) = Eigen::Vector3d::Zero(); + + map(pose.qWorldFromDriverRotation) = Eigen::Quaterniond::Identity(); + map(pose.qDriverFromHeadRotation) = Eigen::Quaterniond::Identity(); + //pose.qWorldFromDriverRotation = HmdQuaternion_Init(1, 0, 0, 0); + //pose.qDriverFromHeadRotation = HmdQuaternion_Init(1, 0, 0, 0); + + // Position + Eigen::Vector3d::Map(pose.vecPosition) = osvr::util::vecMap(report->pose.translation); + + // Position velocity and acceleration are not currently consistently provided + Eigen::Vector3d::Map(pose.vecVelocity) = Eigen::Vector3d::Zero(); + Eigen::Vector3d::Map(pose.vecAcceleration) = Eigen::Vector3d::Zero(); + + // Orientation + map(pose.qRotation) = osvr::util::fromQuat(report->pose.rotation); + + // Angular velocity and acceleration are not currently consistently provided + Eigen::Vector3d::Map(pose.vecAngularVelocity) = Eigen::Vector3d::Zero(); + Eigen::Vector3d::Map(pose.vecAngularAcceleration) = Eigen::Vector3d::Zero(); + + pose.result = vr::TrackingResult_Running_OK; + pose.poseIsValid = true; + //pose.willDriftInYaw = true; + //pose.shouldApplyHeadModel = true; + pose.deviceIsConnected = true; + + self->pose_ = pose; + self->driver_host_->TrackedDevicePoseUpdated(self->m_ControllerIndex + 1, self->pose_); /// @fixme figure out ID correctly, don't hardcode like this +} + +void OSVRTrackedDeviceController::ControllerButtonCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_ButtonReport* report) +{ + if (!userdata) + return; + + auto* self = static_cast(userdata); + + /*if (report->state != OSVR_BUTTON_NOT_PRESSED) + self->logger_->Log(("Some button report channel:" + std::to_string(report->sensor) + " state:" + std::to_string(report->state) + "\n").c_str());*/ + + vr::EVRButtonId buttonID; + if ((report->sensor >= 0 && report->sensor <= 7) || (report->sensor >= 32 && report->sensor <= 36)) + buttonID = static_cast(report->sensor); + else if (report->sensor >= 8 && report->sensor <= 12) + buttonID = static_cast(report->sensor + 24); + else + return; + + if (report->state == OSVR_BUTTON_PRESSED) + self->driver_host_->TrackedDeviceButtonPressed(self->m_ControllerIndex + 1, buttonID, 0); + else + self->driver_host_->TrackedDeviceButtonUnpressed(self->m_ControllerIndex + 1, buttonID, 0); +} + +void OSVRTrackedDeviceController::ControllerTriggerCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_AnalogReport* report) +{ + if (!userdata) + return; + + auto* analogInterface = static_cast(userdata); + OSVRTrackedDeviceController* self = analogInterface->parentController; + + analogInterface->x = report->state; + + vr::VRControllerAxis_t axisState; + axisState.x = (float)analogInterface->x; + self->driver_host_->TrackedDeviceAxisUpdated(self->m_ControllerIndex + 1, analogInterface->axisIndex, axisState); + //self->logger_->Log(("Some Trigger report channel:" + std::to_string(analogInterface->axisIndex) + " state:" + std::to_string(analogInterface->x) + "\n").c_str()); +} + +void OSVRTrackedDeviceController::ControllerJoystickXCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_AnalogReport* report) +{ + if (!userdata) + return; + + auto* analogInterface = static_cast(userdata); + OSVRTrackedDeviceController* self = analogInterface->parentController; + + analogInterface->x = report->state; + + vr::VRControllerAxis_t axisState; + axisState.x = (float)analogInterface->x; + axisState.y = (float)analogInterface->y; + self->driver_host_->TrackedDeviceAxisUpdated(self->m_ControllerIndex + 1, analogInterface->axisIndex, axisState); + + //self->logger_->Log(("Some JoystickX report channel:" + std::to_string(analogInterface->axisIndex) + " state:" + std::to_string(analogInterface->x) + "\n").c_str()); +} + +void OSVRTrackedDeviceController::ControllerJoystickYCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_AnalogReport* report) +{ + if (!userdata) + return; + + auto* analogInterface = static_cast(userdata); + OSVRTrackedDeviceController* self = analogInterface->parentController; + + analogInterface->y = report->state; + + vr::VRControllerAxis_t axisState; + axisState.x = (float)analogInterface->x; + axisState.y = (float)analogInterface->y; + self->driver_host_->TrackedDeviceAxisUpdated(self->m_ControllerIndex + 1, analogInterface->axisIndex, axisState); + + //self->logger_->Log(("Some JoystickY report channel:" + std::to_string(analogInterface->axisIndex) + " state:" + std::to_string(analogInterface->y) + "\n").c_str()); +} + +const char* OSVRTrackedDeviceController::GetId() +{ + /// @todo When available, return the actual unique ID of the HMD + return m_ControllerName.c_str(); +} \ No newline at end of file diff --git a/src/OSVRTrackedDeviceController.h b/src/OSVRTrackedDeviceController.h new file mode 100644 index 0000000..13b20ba --- /dev/null +++ b/src/OSVRTrackedDeviceController.h @@ -0,0 +1,205 @@ +/** @file +@brief OSVR tracked device + +@date 2015 + +@author +Sensics, Inc. + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_OSVRTrackedDeviceController_h_GUID_128E3B29_F5FC_4221_9B38_14E3F402E645 +#define INCLUDED_OSVRTrackedDeviceController_h_GUID_128E3B29_F5FC_4221_9B38_14E3F402E645 + + +#define NUM_BUTTONS 64 +#define NUM_TOUCHPAD 1 // only SteamVR Axis 0 for the moment (not implemented yet) +#define NUM_TRIGGER 1 // only SteamVR Axis 1 for the moment +#define NUM_JOYSTICKS 3 // only SteamVR Axis 2,3,4 for the moment (there is always x and y in one joystick) +#define NUM_AXIS 5 + +// Internal Includes +#include "osvr_compiler_detection.h" // for OSVR_OVERRIDE + +// OpenVR includes +#include + +// Library/third-party includes +#include +#include + +// Standard includes +#include + +class OSVRTrackedDeviceController; + +class AnalogInterface +{ +public: + osvr::clientkit::Interface analogInterfaceX; + osvr::clientkit::Interface analogInterfaceY; + + OSVRTrackedDeviceController* parentController; + + vr::EVRControllerAxisType axisType; + double x; + double y; + int axisIndex; +}; + + +class OSVRTrackedDeviceController : public vr::ITrackedDeviceServerDriver, public vr::IVRControllerComponent { + friend class ServerDriver_OSVR; +public: + OSVRTrackedDeviceController(int controllerIndex, osvr::clientkit::ClientContext& context, vr::IServerDriverHost* driver_host, vr::IDriverLog* driver_log = nullptr); + + virtual ~OSVRTrackedDeviceController(); + // ------------------------------------ + // Management Methods + // ------------------------------------ + /** + * This is called before an HMD is returned to the application. It will + * always be called before any display or tracking methods. Memory and + * processor use by the ITrackedDeviceServerDriver object should be kept to + * a minimum until it is activated. The pose listener is guaranteed to be + * valid until Deactivate is called, but should not be used after that + * point. + */ + virtual vr::EVRInitError Activate(uint32_t object_id) OSVR_OVERRIDE; + + /** + * This is called when The VR system is switching from this Hmd being the + * active display to another Hmd being the active display. The driver should + * clean whatever memory and thread use it can when it is deactivated. + */ + virtual void Deactivate() OSVR_OVERRIDE; + + /** + * Handles a request from the system to power off this device. + */ + virtual void PowerOff() OSVR_OVERRIDE; + + /** + * Requests a component interface of the driver for device-specific + * functionality. The driver should return NULL if the requested interface + * or version is not supported. + */ + virtual void* GetComponent(const char* component_name_and_version) OSVR_OVERRIDE; + + /** + * A VR Client has made this debug request of the driver. The set of valid + * requests is entirely up to the driver and the client to figure out, as is + * the format of the response. Responses that exceed the length of the + * supplied buffer should be truncated and null terminated. + */ + virtual void DebugRequest(const char* request, char* response_buffer, uint32_t response_buffer_size) OSVR_OVERRIDE; + + // ------------------------------------ + // Controller Methods + // ------------------------------------ + + /** Gets the current state of a controller. */ + virtual vr::VRControllerState_t GetControllerState() OSVR_OVERRIDE; + + /** Returns a uint64 property. If the property is not available this function will return 0. */ + virtual bool TriggerHapticPulse(uint32_t unAxisId, uint16_t usPulseDurationMicroseconds) OSVR_OVERRIDE; + + // ------------------------------------ + // Tracking Methods + // ------------------------------------ + virtual vr::DriverPose_t GetPose() OSVR_OVERRIDE; + + // ------------------------------------ + // Property Methods + // ------------------------------------ + + /** + * Returns a bool property. If the property is not available this function + * will return false. + */ + virtual bool GetBoolTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) OSVR_OVERRIDE; + + /** + * Returns a float property. If the property is not available this function + * will return 0. + */ + virtual float GetFloatTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) OSVR_OVERRIDE; + + /** + * Returns an int property. If the property is not available this function + * will return 0. + */ + virtual int32_t GetInt32TrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) OSVR_OVERRIDE; + + /** + * Returns a uint64 property. If the property is not available this function + * will return 0. + */ + virtual uint64_t GetUint64TrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) OSVR_OVERRIDE; + + /** + * Returns a matrix property. If the device index is not valid or the + * property is not a matrix type, this function will return identity. + */ + virtual vr::HmdMatrix34_t GetMatrix34TrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError* error) OSVR_OVERRIDE; + + /** + * Returns a string property. If the property is not available this function + * will return 0 and @p error will be set to an error. Otherwise it returns + * the length of the number of bytes necessary to hold this string including + * the trailing null. If the buffer is too small the error will be + * @c TrackedProp_BufferTooSmall. Strings will generally fit in buffers of + * @c k_unTrackingStringSize characters. Drivers may not return strings longer + * than @c k_unMaxPropertyStringSize. + */ + virtual uint32_t GetStringTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, char* value, uint32_t buffer_size, vr::ETrackedPropertyError* error) OSVR_OVERRIDE; + +protected: + const char* GetId(); + +private: + void FreeInterfaces(); + + std::string GetStringTrackedDeviceProperty(vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *error); + + /** + * Callback function which is called whenever new data has been received + * from the tracker. + */ + static void ControllerTrackerCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_PoseReport* report); + static void ControllerButtonCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_ButtonReport* report); + static void ControllerTriggerCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_AnalogReport* report); + static void ControllerJoystickXCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_AnalogReport* report); + static void ControllerJoystickYCallback(void* userdata, const OSVR_TimeValue* timestamp, const OSVR_AnalogReport* report); + + std::string m_ControllerName; + int m_ControllerIndex; + osvr::clientkit::ClientContext& m_Context; + vr::IDriverLog* logger_ = nullptr; + vr::IServerDriverHost* driver_host_ = nullptr; + osvr::clientkit::Interface m_TrackerInterface; + osvr::clientkit::Interface m_ButtonInterface[NUM_BUTTONS]; + int m_NumAxis; + AnalogInterface m_AnalogInterface[NUM_AXIS]; + + vr::DriverPose_t pose_; + vr::ETrackedDeviceClass deviceClass_; + +}; + +#endif // INCLUDED_OSVRTrackedDevice_h_GUID_128E3B29_F5FC_4221_9B38_14E3F402E645 + diff --git a/src/ServerDriver_OSVR.cpp b/src/ServerDriver_OSVR.cpp index 9cf9c40..3440be5 100644 --- a/src/ServerDriver_OSVR.cpp +++ b/src/ServerDriver_OSVR.cpp @@ -26,6 +26,7 @@ #include "ServerDriver_OSVR.h" #include "OSVRTrackedDevice.h" // for OSVRTrackedDevice +#include "OSVRTrackedDeviceController.h" // for OSVRTrackedDeviceController #include "platform_fixes.h" // strcasecmp #include "make_unique.h" // for std::make_unique @@ -56,40 +57,47 @@ vr::EVRInitError ServerDriver_OSVR::Init(vr::IDriverLog* driver_log, vr::IServer const std::string display_description = context_->getStringParameter("/display"); trackedDevices_.emplace_back(std::make_unique(display_description, *(context_.get()), driver_host, logger_)); + trackedControllerDevices_.emplace_back(std::make_unique(0, *(context_.get()), driver_host, logger_)); + trackedControllerDevices_.emplace_back(std::make_unique(1, *(context_.get()), driver_host, logger_)); + return vr::VRInitError_None; } void ServerDriver_OSVR::Cleanup() { trackedDevices_.clear(); + trackedControllerDevices_.clear(); context_.reset(); } uint32_t ServerDriver_OSVR::GetTrackedDeviceCount() { - std::string msg = "ServerDriver_OSVR::GetTrackedDeviceCount(): Detected " + std::to_string(trackedDevices_.size()) + " tracked devices.\n"; - logger_->Log(msg.c_str()); - return trackedDevices_.size(); + std::string msg = "ServerDriver_OSVR::GetTrackedDeviceCount(): Detected " + std::to_string(trackedDevices_.size() + trackedControllerDevices_.size()) + " tracked devices.\n"; + logger_->Log(msg.c_str()); + return trackedDevices_.size() + trackedControllerDevices_.size(); } vr::ITrackedDeviceServerDriver* ServerDriver_OSVR::GetTrackedDeviceDriver(uint32_t index, const char* interface_version) { - if (0 != strcasecmp(interface_version, vr::ITrackedDeviceServerDriver_Version)) { - std::string msg = "ServerDriver_OSVR::GetTrackedDeviceDriver(): ERROR: Incompatible SteamVR version!\n"; - logger_->Log(msg.c_str()); - return NULL; - } + if (0 != strcasecmp(interface_version, vr::ITrackedDeviceServerDriver_Version)) { + std::string msg = "ServerDriver_OSVR::GetTrackedDeviceDriver(): ERROR: Incompatible SteamVR version!\n"; + logger_->Log(msg.c_str()); + return NULL; + } - if (index >= trackedDevices_.size()) { - std::string msg = "ServerDriver_OSVR::GetTrackedDeviceDriver(): ERROR: Index " + std::to_string(index) + " is out of range [0.." + std::to_string(trackedDevices_.size()) + "].\n"; - logger_->Log(msg.c_str()); - return NULL; - } + if (index >= trackedDevices_.size() + trackedControllerDevices_.size()) { + std::string msg = "ServerDriver_OSVR::GetTrackedDeviceDriver(): ERROR: Index " + std::to_string(index) + " is out of range [0.." + std::to_string(trackedDevices_.size() + trackedControllerDevices_.size()) + "].\n"; + logger_->Log(msg.c_str()); + return NULL; + } - std::string msg = "ServerDriver_OSVR::GetTrackedDeviceDriver(): Returning tracked device " + std::to_string(index) + ".\n"; - logger_->Log(msg.c_str()); + std::string msg = "ServerDriver_OSVR::GetTrackedDeviceDriver(): Returning tracked device " + std::to_string(index) + ".\n"; + logger_->Log(msg.c_str()); + + if (index >= trackedDevices_.size()) + return trackedControllerDevices_[index - trackedDevices_.size()].get(); - return trackedDevices_[index].get(); + return trackedDevices_[index].get(); } vr::ITrackedDeviceServerDriver* ServerDriver_OSVR::FindTrackedDeviceDriver(const char* id, const char* interface_version) @@ -108,6 +116,14 @@ vr::ITrackedDeviceServerDriver* ServerDriver_OSVR::FindTrackedDeviceDriver(const } } + for (auto& tracked_device : trackedControllerDevices_) { + if (0 == std::strcmp(id, tracked_device->GetId())) { + std::string msg = "ServerDriver_OSVR::FindTrackedDeviceDriver(): Returning tracked device " + std::string(id) + ".\n"; + logger_->Log(msg.c_str()); + return tracked_device.get(); + } + } + std::string msg = "ServerDriver_OSVR::FindTrackedDeviceDriver(): ERROR: Failed to locate device named '" + std::string(id) + "'.\n"; logger_->Log(msg.c_str()); diff --git a/src/ServerDriver_OSVR.h b/src/ServerDriver_OSVR.h index 2a365e2..1efde55 100644 --- a/src/ServerDriver_OSVR.h +++ b/src/ServerDriver_OSVR.h @@ -27,6 +27,7 @@ // Internal Includes #include "OSVRTrackedDevice.h" // for OSVRTrackedDevice +#include "OSVRTrackedDeviceController.h" // for OSVRTrackedDeviceController #include "osvr_compiler_detection.h" // for OSVR_OVERRIDE // Library/third-party includes @@ -115,6 +116,7 @@ class ServerDriver_OSVR : public vr::IServerTrackedDeviceProvider { private: std::vector> trackedDevices_; + std::vector> trackedControllerDevices_; std::unique_ptr context_; vr::IDriverLog* logger_; };