OSVR-Vive

DriverWrapper类(DriverWrapper.h),主要有:

1.openvr_driver.h中接口:


vr::ITrackedDeviceServerDriver:

@brief:表示一个追踪设备。在驱动动态库中实现,如vive的driver_lighthouse.dll,运行时被vrserver加载,可用ITrackedDeviceServerProvider对象的Cleanup方法卸载。

vr::IVRServerDriverHost:

@brief:向server发送各类事件通知(Pose或Button按键信息等),提供以下函数功能:

1>.TrackedDeviceAdded:通知server一个追踪设备已经被添加。若返回true,则server将调用该设备的Active函数,若返回false,则该设备不会被active

2>.TrackedDevicePoseUpdated:往server发送pose信息

3>.TrackedDeviceAxisUpdated:往server发送x,y坐标轴信息(Joystick触摸板)

4>.GetRawTrackedDevicePoses:v1.0.7版本添加的函数,为驱动提供设备裸Pose信息


vr::IServerTrackedDeviceProvider:

@brief:用于查询发送追踪设备信息并往server发送,可理解为一个client与server的中间桥梁作用,在驱动dll动态库中实现,运行时被vrserver加载调用。提供以下函数:

1>.HmdError Init( IDriverLog *pDriverLog, vr::IServerDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir ):

@brief:初始化驱动,该函数最先被调用(在任何函数之前)。当且仅当返回HmdError_None时,dll驱动才会被调用。

@pchUserDriverConfigDir:驱动用户配置文件的绝对路径,如:Steam\config

@pchDriverInstallDir:驱动根目录绝对路径,如:Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64

@note:在V1.0.6之后,若provider含有HMD,则需在Init返回前,调用TrackedDeviceAdded添加HMD的详细信息。其他设备则可在任何时候调用TrackedDeviceAdded添加。

后续版本被virtual EVRInitError Init( IVRDriverContext *pDriverContext ) = 0所取代。

其中IVRDriverContext在后面分析。

2>.virtual void Cleanup():

@brief: 卸载vr::ITrackedDeviceServerDriver声明的驱动。

3>.virtual const char * const *GetInterfaceVersions() = 0:

@brief:返回驱动使用的vr::ITrackedDeviceServerDriver接口的版本号

4>.virtual void RunFrame() = 0:

@brief:在server的main循环中被调用,通过vr::ITrackedDeviceServerDriver提供的数据接口循环往server发送pose或button或axis等信息

5>.uint32_t GetTrackedDeviceCount():

@brief:返回驱动连接追踪设备的数量。在启动时,可用来初始化驱动的追踪设备链表。


vr::IVRDriverContext:

@brief:获取驱动所需使用到的接口以及获取驱动handle

1>.virtual void *GetGenericInterface( const char *pchInterfaceVersion, EVRInitError *peError = nullptr ) = 0:

@berief:通过版本号获取接口,以供后续使用。如:

m_pVRServerDriverHost = (IVRServerDriverHost *)VRDriverContext()->GetGenericInterface( IVRServerDriverHost_Version, &eError );  
static const char *IVRServerDriverHost_Version = "IVRServerDriverHost_004"; 
@note:在新版本vr::IServerTrackedDeviceProvider的Init使用到。

比如:

EVRInitError CServerDriver_Sample::Init( vr::IVRDriverContext *pDriverContext )  
{  
    VR_INIT_SERVER_DRIVER_CONTEXT( pDriverContext );  
    InitDriverLog( vr::VRDriverLog() );  
  
    m_pNullHmdLatest = new CSampleDeviceDriver();  
    vr::VRServerDriverHost()->TrackedDeviceAdded( m_pNullHmdLatest->GetSerialNumber().c_str(), vr::TrackedDeviceClass_HMD, m_pNullHmdLatest );  
    return VRInitError_None;  
}  
在VR_INIT_SERVER_DRIVER_CONTEXT( pDriverContext )初始化m_pVRServerDriverHost,m_pVRSettings,

m_propertyHelpers,m_pVRDriverLog,m_pVRDriverManager,m_pVRResources接口,以供后续调用它们的方法。

2>.virtual DriverHandle_t GetDriverHandle() = 0:
@brief:返回该驱动属性容器的句柄

vr::IVRSettings:

@brief:提供接口用来获取类似Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings文件下的属性字段

vr::IVRDriverLog:

@virtual void Log( const char *pchLogMessage ) = 0:

将log输出到log文件,并在log文件名前加驱动名前缀。

vr::IVRProperties:

@brief:对设备的属性进行读写,设备属性有追踪设备系统名,产品型号,产品序列号等。

enum ETrackedDeviceProperty  
{  
    Prop_Invalid                                = 0,  
  
    // general properties that apply to all device classes  
    Prop_TrackingSystemName_String              = 1000,  
    Prop_ModelNumber_String                     = 1001,  
    Prop_SerialNumber_String                    = 1002,  
    Prop_RenderModelName_String                 = 1003,  
    Prop_WillDriftInYaw_Bool                    = 1004,  
    Prop_ManufacturerName_String                = 1005,  
    Prop_TrackingFirmwareVersion_String         = 1006,  
    Prop_HardwareRevision_String                = 1007,  
    Prop_AllWirelessDongleDescriptions_String   = 1008,  
    Prop_ConnectedWirelessDongle_String         = 1009,  
    Prop_DeviceIsWireless_Bool                  = 1010,  
    Prop_DeviceIsCharging_Bool                  = 1011,  
    Prop_DeviceBatteryPercentage_Float          = 1012, // 0 is empty, 1 is full  
    Prop_StatusDisplayTransform_Matrix34        = 1013,  
    Prop_Firmware_UpdateAvailable_Bool          = 1014,  
    Prop_Firmware_ManualUpdate_Bool             = 1015,  
    Prop_Firmware_ManualUpdateURL_String        = 1016,  
    Prop_HardwareRevision_Uint64                = 1017,  
    Prop_FirmwareVersion_Uint64                 = 1018,  
    Prop_FPGAVersion_Uint64                     = 1019,  
    Prop_VRCVersion_Uint64                      = 1020,  
    Prop_RadioVersion_Uint64                    = 1021,  
    Prop_DongleVersion_Uint64                   = 1022,  
    Prop_BlockServerShutdown_Bool               = 1023,  
    Prop_CanUnifyCoordinateSystemWithHmd_Bool   = 1024,  
    Prop_ContainsProximitySensor_Bool           = 1025,  
    Prop_DeviceProvidesBatteryStatus_Bool       = 1026,  
    Prop_DeviceCanPowerOff_Bool                 = 1027,  
    Prop_Firmware_ProgrammingTarget_String      = 1028,  
    Prop_DeviceClass_Int32                      = 1029,  
    Prop_HasCamera_Bool                         = 1030,  
    Prop_DriverVersion_String                   = 1031,  
    Prop_Firmware_ForceUpdateRequired_Bool      = 1032,  
    Prop_ViveSystemButtonFixRequired_Bool       = 1033,  
    Prop_ParentDriver_Uint64                    = 1034,  
    Prop_ResourceRoot_String                    = 1035,  
  
    // Properties that are unique to TrackedDeviceClass_HMD  
    Prop_ReportsTimeSinceVSync_Bool             = 2000,  
    Prop_SecondsFromVsyncToPhotons_Float        = 2001,  
    Prop_DisplayFrequency_Float                 = 2002,  
    Prop_UserIpdMeters_Float                    = 2003,  
    Prop_CurrentUniverseId_Uint64               = 2004,   
    Prop_PreviousUniverseId_Uint64              = 2005,   
    Prop_DisplayFirmwareVersion_Uint64          = 2006,  
    Prop_IsOnDesktop_Bool                       = 2007,  
    Prop_DisplayMCType_Int32                    = 2008,  
    Prop_DisplayMCOffset_Float                  = 2009,  
    Prop_DisplayMCScale_Float                   = 2010,  
    Prop_EdidVendorID_Int32                     = 2011,  
    Prop_DisplayMCImageLeft_String              = 2012,  
    Prop_DisplayMCImageRight_String             = 2013,  
    Prop_DisplayGCBlackClamp_Float              = 2014,  
    Prop_EdidProductID_Int32                    = 2015,  
    Prop_CameraToHeadTransform_Matrix34         = 2016,  
    Prop_DisplayGCType_Int32                    = 2017,  
    Prop_DisplayGCOffset_Float                  = 2018,  
    Prop_DisplayGCScale_Float                   = 2019,  
    Prop_DisplayGCPrescale_Float                = 2020,  
    Prop_DisplayGCImage_String                  = 2021,  
    Prop_LensCenterLeftU_Float                  = 2022,  
    Prop_LensCenterLeftV_Float                  = 2023,  
    Prop_LensCenterRightU_Float                 = 2024,  
    Prop_LensCenterRightV_Float                 = 2025,  
    Prop_UserHeadToEyeDepthMeters_Float         = 2026,  
    Prop_CameraFirmwareVersion_Uint64           = 2027,  
    Prop_CameraFirmwareDescription_String       = 2028,  
    Prop_DisplayFPGAVersion_Uint64              = 2029,  
    Prop_DisplayBootloaderVersion_Uint64        = 2030,  
    Prop_DisplayHardwareVersion_Uint64          = 2031,  
    Prop_AudioFirmwareVersion_Uint64            = 2032,  
    Prop_CameraCompatibilityMode_Int32          = 2033,  
    Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034,  
    Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035,  
    Prop_DisplaySuppressed_Bool                 = 2036,  
    Prop_DisplayAllowNightMode_Bool             = 2037,  
    Prop_DisplayMCImageWidth_Int32              = 2038,  
    Prop_DisplayMCImageHeight_Int32             = 2039,  
    Prop_DisplayMCImageNumChannels_Int32        = 2040,  
    Prop_DisplayMCImageData_Binary              = 2041,  
    Prop_SecondsFromPhotonsToVblank_Float       = 2042,  
  
    // Properties that are unique to TrackedDeviceClass_Controller  
    Prop_AttachedDeviceId_String                = 3000,  
    Prop_SupportedButtons_Uint64                = 3001,  
    Prop_Axis0Type_Int32                        = 3002, // Return value is of type EVRControllerAxisType  
    Prop_Axis1Type_Int32                        = 3003, // Return value is of type EVRControllerAxisType  
    Prop_Axis2Type_Int32                        = 3004, // Return value is of type EVRControllerAxisType  
    Prop_Axis3Type_Int32                        = 3005, // Return value is of type EVRControllerAxisType  
    Prop_Axis4Type_Int32                        = 3006, // Return value is of type EVRControllerAxisType  
    Prop_ControllerRoleHint_Int32               = 3007, // Return value is of type ETrackedControllerRole  
  
    // Properties that are unique to TrackedDeviceClass_TrackingReference  
    Prop_FieldOfViewLeftDegrees_Float           = 4000,  
    Prop_FieldOfViewRightDegrees_Float          = 4001,  
    Prop_FieldOfViewTopDegrees_Float            = 4002,  
    Prop_FieldOfViewBottomDegrees_Float         = 4003,  
    Prop_TrackingRangeMinimumMeters_Float       = 4004,  
    Prop_TrackingRangeMaximumMeters_Float       = 4005,  
    Prop_ModeLabel_String                       = 4006,  
  
    // Properties that are used for user interface like icons names  
    Prop_IconPathName_String                        = 5000, // usually a directory named "icons"  
    Prop_NamedIconPathDeviceOff_String              = 5001, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
    Prop_NamedIconPathDeviceSearching_String        = 5002, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
    Prop_NamedIconPathDeviceSearchingAlert_String   = 5003, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
    Prop_NamedIconPathDeviceReady_String            = 5004, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
    Prop_NamedIconPathDeviceReadyAlert_String       = 5005, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
    Prop_NamedIconPathDeviceNotReady_String         = 5006, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
    Prop_NamedIconPathDeviceStandby_String          = 5007, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
    Prop_NamedIconPathDeviceAlertLow_String         = 5008, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others  
  
    // Properties that are used by helpers, but are opaque to applications  
    Prop_DisplayHiddenArea_Binary_Start             = 5100,  
    Prop_DisplayHiddenArea_Binary_End               = 5150,  
  
    // Properties that are unique to drivers  
    Prop_UserConfigPath_String                  = 6000,  
    Prop_InstallPath_String                     = 6001,  
    Prop_HasDisplayComponent_Bool               = 6002,  
    Prop_HasControllerComponent_Bool            = 6003,  
    Prop_HasCameraComponent_Bool                = 6004,  
    Prop_HasDriverDirectModeComponent_Bool      = 6005,  
    Prop_HasVirtualDisplayComponent_Bool        = 6006,  
  
    // Vendors are free to expose private debug data in this reserved region  
    Prop_VendorSpecific_Reserved_Start          = 10000,  
    Prop_VendorSpecific_Reserved_End            = 10999,  
}  

在vr::ITrackedDeviceServerDriver设备驱动中使用如下:

virtual EVRInitError Activate( vr::TrackedDeviceIndex_t unObjectId )  
{  
        m_unObjectId = unObjectId;  
        m_ulPropertyContainer = vr::VRProperties()->TrackedDeviceToPropertyContainer( m_unObjectId );  
  
  
        vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, Prop_ModelNumber_String, m_sModelNumber.c_str() );  
        vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, Prop_RenderModelName_String, m_sModelNumber.c_str() );  
        vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_UserIpdMeters_Float, m_flIPD );  
        vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_UserHeadToEyeDepthMeters_Float, 0.f );  
        vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_DisplayFrequency_Float, m_flDisplayFrequency );  
        vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_SecondsFromVsyncToPhotons_Float, m_flSecondsFromVsyncToPhotons );  
  
        // return a constant that's not 0 (invalid) or 1 (reserved for Oculus)  
        vr::VRProperties()->SetUint64Property( m_ulPropertyContainer, Prop_CurrentUniverseId_Uint64, 2 );  
  
        // avoid "not fullscreen" warnings from vrmonitor  
        vr::VRProperties()->SetBoolProperty( m_ulPropertyContainer, Prop_IsOnDesktop_Bool, false );  
  
        // Icons can be configured in code or automatically configured by an external file "drivername\resources\driver.vrresources".  
        // Icon properties NOT configured in code (post Activate) are then auto-configured by the optional presence of a driver's "drivername\resources\driver.vrresources".  
        // In this manner a driver can configure their icons in a flexible data driven fashion by using an external file.  
        //  
        // The structure of the driver.vrresources file allows a driver to specialize their icons based on their HW.  
        // Keys matching the value in "Prop_ModelNumber_String" are considered first, since the driver may have model specific icons.  
        // An absence of a matching "Prop_ModelNumber_String" then considers the ETrackedDeviceClass ("HMD", "Controller", "GenericTracker", "TrackingReference")  
        // since the driver may have specialized icons based on those device class names.  
        //  
        // An absence of either then falls back to the "system.vrresources" where generic device class icons are then supplied.  
        //  
        // Please refer to "bin\drivers\sample\resources\driver.vrresources" which contains this sample configuration.  
        //  
        // "Alias" is a reserved key and specifies chaining to another json block.  
        //  
        // In this sample configuration file (overly complex FOR EXAMPLE PURPOSES ONLY)....  
        //  
        // "Model-v2.0" chains through the alias to "Model-v1.0" which chains through the alias to "Model-v Defaults".  
        //  
        // Keys NOT found in "Model-v2.0" would then chase through the "Alias" to be resolved in "Model-v1.0" and either resolve their or continue through the alias.  
        // Thus "Prop_NamedIconPathDeviceAlertLow_String" in each model's block represent a specialization specific for that "model".  
        // Keys in "Model-v Defaults" are an example of mapping to the same states, and here all map to "Prop_NamedIconPathDeviceOff_String".  
        //  
        bool bSetupIconUsingExternalResourceFile = true;  
        if ( !bSetupIconUsingExternalResourceFile )  
        {  
            // Setup properties directly in code.  
            // Path values are of the form {drivername}\icons\some_icon_filename.png  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceOff_String, "{sample}/icons/headset_sample_status_off.png" );  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceSearching_String, "{sample}/icons/headset_sample_status_searching.gif" );  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceSearchingAlert_String, "{sample}/icons/headset_sample_status_searching_alert.gif" );  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceReady_String, "{sample}/icons/headset_sample_status_ready.png" );  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceReadyAlert_String, "{sample}/icons/headset_sample_status_ready_alert.png" );  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceNotReady_String, "{sample}/icons/headset_sample_status_error.png" );  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceStandby_String, "{sample}/icons/headset_sample_status_standby.png" );  
            vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceAlertLow_String, "{sample}/icons/headset_sample_status_ready_low.png" );  
        }  
  
        return VRInitError_None;  
}  
2.自定义类:

DeviceHolder类:


1>.addAndActivateDevice():代码如下:

IdReturnValue  
       addAndActivateDevice(vr::ITrackedDeviceServerDriver *dev) {  
           /// check to make sure it's not null and not already in there  
           if (!dev) {  
               return IdReturnValue::makeError();  
           }  
           auto existing = findDevice(dev);//查找  
           if (existing) {  
               /// @todo do we return an error or the existing location? This  
               /// returns the existing location after re-activating.  
               dev->Activate(existing.value);  
               return existing;  
           }  
           auto newId = static_cast<std::uint32_t>(devices_.size());  
           devices_.push_back(dev);  
           dev->Activate(newId);  
           return IdReturnValue::makeValue(newId);  
       }  


@brief:查找容器devices_中是否存在dev设备驱动,若存在,则active它并返回它的id号;反之,则添加进devices_并返回id号。

2>.addAndActivateDeviceAt():代码如下:

/// Add and activate a device at a reserved id.  
        IdReturnValue  
        addAndActivateDeviceAt(vr::ITrackedDeviceServerDriver *dev,  
                               std::uint32_t idx) {  
            /// check to make sure it's not null and not already in there  
            if (!dev) {  
                return IdReturnValue::makeError();  
            }  
            auto existing = findDevice(dev);  
            if (existing && existing.value != idx) {  
                // if we already found it in there and it's not at the desired  
                // index...  
                return IdReturnValue(existing.value, false);  
            }  
  
            if (existing) {  
                // well, in this case, we might need to just activate it again.  
                dev->Activate(idx);  
                return IdReturnValue::makeValue(idx);  
            }  
  
            if (!(idx < devices_.size())) {  
                // OK, we need to reserve more room.  
                reserveIds(idx + 1);  
            }  
  
            if (devices_[idx]) {  
                // there's already somebody else there...  
                return IdReturnValue::makeError();  
            }  
  
            /// Finally, if we made it through that, it's our turn.  
            devices_[idx] = dev;  
            dev->Activate(idx);  
  
            return IdReturnValue::makeValue(idx);  
        }  
@brief:激活指定idx的设备。

InterfaceVersionSupport类:

@brief:辅助类,用于管理接口版本号

1>.InterfaceVersionSupport() : supportedInterfaces_(populate()) {}

@brief:接收populate的返回值

2>.populate:

/// Function to create and populate the supported interface  
      /// container, so the object's data member may be const.  
      static Container populate() {  
          Container ret;  
          // Populate a vector with all the supported interfaces.  
          for_each_const_string_array(  
              vr::k_InterfaceVersions,  
              [&](const char *str) { ret.emplace_back(str); });  
  
          // so we can use binary_search  
          std::sort(ret.begin(), ret.end());  
          return ret;  
      }  

@brief:将openvr_driver.h中声明的vr::k_InterfaceVersions传入lambda函数,加入vector。之后按序列从小到大排列,
并返回赋给supportedInterfaces_

namespace vr  
{  
    static const char * const k_InterfaceVersions[] =  
    {  
        IVRSettings_Version,  
        ITrackedDeviceServerDriver_Version,  
        IVRDisplayComponent_Version,  
        IVRDriverDirectModeComponent_Version,  
        IVRControllerComponent_Version,  
        IVRCameraComponent_Version,  
        IServerTrackedDeviceProvider_Version,  
        IVRWatchdogProvider_Version,  
        IVRVirtualDisplay_Version,  
        IVRDriverManager_Version,  
        IVRResources_Version,  
        nullptr  
    };  
...  
  
}  
2>.inline bool isInterfaceNameWeCareAbout(std::string const &interfaceName)

@brief:用于检查传入的接口类是否为该驱动所care的接口类

/// A list of just the interface names we actually use.  
        static const auto interfaceNamesWeCareAbout = {  
            "ITrackedDeviceServerDriver", "IVRDisplayComponent",  
            "IVRControllerComponent", //< @todo do we actually use/cast to  
                                      // this interface?  
            "IServerTrackedDeviceProvider", "IVRWatchdogProvider"};  
  
    } // namespace detail  
  
    inline bool isInterfaceNameWeCareAbout(std::string const &interfaceName) {  
        return std::find(detail::interfaceNamesWeCareAbout.begin(),  
                         detail::interfaceNamesWeCareAbout.end(),  
                         interfaceName) !=  
               detail::interfaceNamesWeCareAbout.end();  
    } 

DriverLoader:
@brief:用来加载一个steamVR driver dll驱动,获取主入口点及其函数调用,这个类是驱动运行的必要条件。
1>. /// Factory function to make a driver loader.
        static std::unique_ptr<DriverLoader>
        make(std::string const &driverRoot, std::string const &driverFile);
@brief:工厂方法生成一个驱动加载对象。


loader_ = DriverLoader::make(locations_.driverRoot,  
                                         locations_.driverFile);  

驱动根目录(driverRoot)如:Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64
驱动文件(driverFile)如:Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64\driver_lighthouse.dll


2>.template <typename InterfaceType>
        ReturnValue<InterfaceType *, int> getInterface()
@brief:获取模板参数InterfaceType指定的接口类。最初由getProvider<vr::IServerTrackedDeviceProvider>调用。

3>.std::string const &getDriverRoot()

@brief:获取根目录,如:

Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64

ChaperoneData:
@brief:一些已知的追踪器空间范围的数据。比如空间界限,游戏空间等。来自于chaperone_info,位于<Steam\config\chaperone_info.vrchap>

1>.struct UniverseData {
            CalibrationType type = CalibrationType::Standing;
            std::array<double, 3> translation;
            double yaw = 0.;
        };

@brief:空间数据。类型:站立。数据:位置信息以及偏航角。

2>.ChaperoneData::ChaperoneData(std::string const &steamConfigDir)
        : impl_(new Impl), configDir_(steamConfigDir)

@brief:从chaperone_info.vrchap文件中获取字段填充成员变量impl_,结构代码如下:

struct ChaperoneData::Impl {  
        Json::Value chaperoneInfo;  
        UniverseDataMap universes;  
        UniverseBaseSerials baseSerials;  
    };  

3>.UniverseData getDataForUniverse(UniverseId universe) const
@brief:获取外设数据。


ChaperoneData::UniverseData  
    ChaperoneData::getDataForUniverse(UniverseId universe) const {  
        auto it = impl_->universes.find(universe);  
        if (it == end(impl_->universes)) {  
            return UniverseData();  
        }  
        return it->second; // ChaperoneData::UniverseData类型  
    }  
@brief:通过universe号获取对应的键值
 
using UniverseDataMap =

        std::map<std::uint64_t, ChaperoneData::UniverseData>;


4>. UniverseId        guessUniverseIdFromBaseStations(BaseStationSerials const &bases);

using BaseStationSerials = std::vector<std::string>;  
  
ChaperoneData::UniverseId ChaperoneData::guessUniverseIdFromBaseStations(  
        BaseStationSerials const &bases) {  
        auto providedSize = bases.size();  
        UniverseId ret = 0;  
        using UniverseRank = std::pair<float, UniverseId>;  
        /// Compare function for heap.  
        auto compare = [](UniverseRank const &a, UniverseRank const &b) {  
            return a.first < b.first;  
        };  
  
        /// Will contain heap of potential universes and their value (a fraction  
        /// of their base stations and provided base stations that were included  
        /// in the base station list provided to the function)  
        std::vector<UniverseRank> potentialUniverses;  
        auto push = [&](float value, UniverseId id) {  
            potentialUniverses.emplace_back(value, id);  
            std::push_heap(begin(potentialUniverses), end(potentialUniverses),  
                           compare);  
        };  
  
        for (auto &univBaseSerial : impl_->baseSerials) {  
            auto const &baseSerials = univBaseSerial.second;  
            std::size_t hits = 0;  
            auto b = begin(baseSerials);  
            auto e = end(baseSerials);  
            /// Count the number of entries that we were given that are also in  
            /// this universe's list.  
            auto found = std::count_if(begin(bases), end(bases),  
                                       [&](std::string const &needle) {  
                                           return std::find(b, e, needle) != e;  
                                       });  
            if (found > 0) {  
                /// This is meant to combine the influence of "found" in both  
                /// providedSize and universe size, and the +1 in the  
                /// denominator is to avoid division by zero.  
                auto weight = 2.f * static_cast<float>(found) /  
                              (baseSerials.size() + providedSize + 1);  
#if 0  
                std::cout << "Guessing produced weight of " << weight << " for "  
                          << univBaseSerial.first << std::endl;  
#endif  
                push(weight, univBaseSerial.first);  
            }  
        }  
        if (!potentialUniverses.empty()) {  
            /// it's a heap, so the best one is always on top.  
            return potentialUniverses.front().second;  
        }  
        return ret;  
    }  

@brief:由基站预测id。


com_osvr_Vive.cpp为OSVR插件一般结构:

OSVR_ReturnCode update(){  
        if (m_startedInSuccess) {  
            return OSVR_RETURN_SUCCESS;  
        }  
  
        if (!m_shouldAttemptDetection) {  
            /// We said we shouldn't and wouldn't try again.  
            return OSVR_RETURN_FAILURE;  
        }  
  
        /// Hand the Vive object off to the OSVR driver.  
        auto startResult = finishViveStartup();// 进入  
        if (startResult) {  
            /// and it started up the rest of the way just fine!  
            /// We'll keep the driver around!  
            m_logger->info("Vive driver finished startup successfully!");  
            m_startedInSuccess = true;  
            return OSVR_RETURN_SUCCESS;  
        }  
  
        m_logger->error("Vive driver startup failed.");  
  
        if (m_shouldAttemptDetection) {  
            m_logger->info(" Unloading to perhaps try again later.");  
        }  
  
        return OSVR_RETURN_FAILURE;  
    }  

finishViveStartup()中调用ViveDriverHost中的start方法。

ViveDriverHost类 :继承自vr::IVRServerDriverHost:
ViveDriverHost::StartResult  
    ViveDriverHost::start(OSVR_PluginRegContext ctx,  
                          osvr::vive::DriverWrapper &&inVive)  
{  
        if (!inVive) {  
            m_logger->error(  
                "Called ViveDriverHost::start() with an invalid vive object!");  
            return StartResult::TemporaryFailure;  
        }  
        /// Take ownership of the Vive.  
        m_vive.reset(new osvr::vive::DriverWrapper(std::move(inVive)));  
  
        /// define the lambda to handle the ServerDriverHost::TrackedDeviceAdded  
        auto handleNewDevice = [&](const char *serialNum,  
                                   ETrackedDeviceClass eDeviceClass,  
                                   ITrackedDeviceServerDriver *pDriver) {  
            auto dev = pDriver;  
            if (!dev) {  
                m_logger->info("null input device");  
                return false;  
            }  
            auto ret = activateDevice(dev, eDeviceClass);  
            if (!ret) {  
                m_logger->error("Device with serial number ")  
                    << serialNum << " couldn't be added to the devices vector.";  
                return false;  
            }  
            NewDeviceReport out{std::string{serialNum}, ret.value};  
            {  
                std::lock_guard<std::mutex> lock(m_mutex);  
                m_newDevices.submitNew(std::move(out), lock);  
            }  
            return true;  
        };  
  
        m_vive->driverHost().onTrackedDeviceAdded = handleNewDevice;  
  
        /// Finish setting up the Vive.  
        try {  
            if (!m_vive->startServerDeviceProvider()) {  
                m_logger->error("Could not start the server device provider in "  
                                "the Vive driver. Exiting.");  
                return StartResult::TemporaryFailure;  
            }  
        } catch (CouldNotGetInterface &e) {  
            m_logger->error("Caught exception trying to start Vive server "  
                            "device provider: ")  
                << e.what();  
            m_logger->error("SteamVR interface version may have changed, may "  
                            "need to be rebuilt against an updated header or "  
                            "use an older SteamVR version. Exiting.");  
            return StartResult::PermanentFailure;  
        }  
  
        /// Check for interface compatibility  
        if (DriverWrapper::InterfaceVersionStatus::InterfaceMismatch ==  
            m_vive->checkServerDeviceProviderInterfaces()) {  
            m_logger->error(  
                "SteamVR lighthouse driver requires unavailable/unsupported "  
                "SteamVR lighthouse driver requires unavailable/unsupported "  
                "interface versions - either too old or too new for this "  
                "build. Specifically, the following critical mismaches: ");  
            for (auto iface : m_vive->getUnsupportedRequestedInterfaces()) {  
                if (isInterfaceNameWeCareAbout(  
                        detail::getInterfaceName(iface))) {  
                    auto supported =  
                        m_vive->getSupportedInterfaceVersions()  
                            .findSupportedVersionOfInterface(iface);  
                    m_logger->error(" - SteamVR lighthouse: ")  
                        << iface << "\t\t OSVR-Vive: " << supported;  
                }  
            }  
            m_logger->error("Cannot continue.\n");  
            return StartResult::PermanentFailure;  
        }  
  
        /// Power the system up.  
        m_vive->serverDevProvider().LeaveStandby();  
  
        /// Reserve ID 0 for the HMD  
        m_vive->devices().reserveIds(1);  
  
        /// Finish setting this up as an OSVR device.  
        /// Create the initialization options  
        OSVR_DeviceInitOptions opts = osvrDeviceCreateInitOptions(ctx);  
  
        osvrDeviceTrackerConfigure(opts, &m_tracker);  
        osvrDeviceAnalogConfigure(opts, &m_analog, NUM_ANALOGS);  
        osvrDeviceButtonConfigure(opts, &m_button, NUM_BUTTONS);  
  
        /// Because the callbacks may not come from the same thread that  
        /// calls RunFrame, we need to be careful to not send directly from  
        /// those callbacks. We can't use an Async device token because the  
        /// waits are too long and they goof up the SteamVR Lighthouse driver.  
        m_dev.initSync(ctx, "Vive", opts);  
  
        /// Send JSON descriptor  
        m_dev.sendJsonDescriptor(com_osvr_Vive_json);  
  
        /// Register update callback  
        m_dev.registerUpdateCallback(this);  
  
        return StartResult::Success;  
    }  

1>.将参数DriverWrapper类对象inVive赋给成员变量m_vive
2>.将lambda函数指针handleNewDevice赋给onTrackedDeviceAdded(由m_vive控制的driverHost类):
lambda函数截获串号(类似hydra_controller1或hydra_controller2之类的字符串形式),设备类别(类似HMD PUCK等)以及
设备驱动。通过参数传入将指定idx的外设添加到容器std::vector<vr::ITrackedDeviceServerDriver *> devices_中
,并激活它,激活后返回它的idx值赋值给ret.value。之后,将serialNum与ret.value构造一个NewDeviceReport类,将该类存入
队列deque_。
3>.将lambda函数赋给 m_vive->driverHost().onTrackedDeviceAdded。将在ServerDeviceProvider启动后,在Init中被调用。
4>.startServerDeviceProvider:
初始化vr::IVRSettings,vr::IVRDriverLog,vr::IVRProperties类对象,并使用它们构建一个vr::DriverContext类对象,再通过
VR_INIT_SERVER_DRIVER_CONTEXT(context_)本质上是给COpenVRDriverContext类的m_pVRSettings,m_pVRDriverLog,m_pVRProperties
赋值。以供后续如TrackedDeviceAdded使用。

#define VR_INIT_SERVER_DRIVER_CONTEXT( pContext ) \  
          { \  
          vr::EVRInitError eError = vr::InitServerDriverContext( pContext ); \  
          if( eError != vr::VRInitError_None ) \  
              return eError; \  
          }  

在将环境准备好之后,serverDeviceProvider_ =
                getProvider<vr::IServerTrackedDeviceProvider>(
                    std::move(loader_), context_);
 
传入模板参数vr::IServerTrackedDeviceProvider, 随后:

template <typename InterfaceType>  
    inline ProviderPtr<InterfaceType>  
    getProvider(std::unique_ptr<DriverLoader> &&loader,  
                vr::IVRDriverContext *context) {  
        static_assert(  
            InterfaceExpectedFromEntryPointTrait<InterfaceType>::value,  
            "Function only valid for those 'provider' interface types "  
            "expected to be provided by the driver entry point.");  
        return detail::getProviderImpl<InterfaceType>(  
            std::move(loader), context, [](SharedDriverLoader const &) {});  
    }  

传入一个lambda函数指针(不捕获时才可转换为函数指针)。

template <typename InterfaceType, typename F>  
        inline ProviderPtr<InterfaceType>  
        getProviderImpl(std::unique_ptr<DriverLoader> &&loader,  
                        vr::IVRDriverContext *context,  
                        F &&driverLoaderFunctor) {  
            using return_type = ProviderPtr<InterfaceType>;  
  
            if (!loader) {  
                return return_type{};  
            }  
            /// Move into local pointer, so if something goes wrong, the driver  
            /// gets unloaded.  
            std::unique_ptr<DriverLoader> myLoader(std::move(loader));  
            auto rawPtr = myLoader->getInterfaceThrowing<InterfaceType>();  
            auto initResults = rawPtr->Init(context);  
            if (vr::VRInitError_None != initResults) {  
                /// Failed, reset the loader pointer to unload the driver.  
                std::cout << "Got error code " << initResults << std::endl;  
                myLoader.reset();  
                return return_type{};  
            }  
  
            /// OK, so this is the interface. Move the loader into a shared  
            /// pointer, make the loader responsible for cleanup of the  
            /// interface, and get the shared pointer of the interface pointer  
            /// returned.  
            SharedDriverLoader sharedLoader(std::move(myLoader));  
            sharedLoader->cleanupInterfaceOnDestruction(rawPtr);  
  
            /// Call the hook  
            (std::forward<F>(driverLoaderFunctor))(sharedLoader);  
  
            /// Create the return value: another shared pointer.  
            /// This is the so-called "aliasing" constructor - this pointer will  
            /// actually keep the DriverLoader alive and do nothing with the  
            /// lifetime of rawPtr (which is why the loader is responsible for  
            /// calling Cleanup, see above)  
            return_type ret(sharedLoader, rawPtr);  
  
            return ret;  
        }  

(std::forward<F>(driverLoaderFunctor))(sharedLoader):钩子获取dll中的接口,与driver_lighthouse.dll衔接。

其中sharedLoader最初由loader_ = DriverLoader::make(locations_.driverRoot, locations_.driverFile);构建而成。

std::unique_ptr<DriverLoader>  
    DriverLoader::make(std::string const &driverRoot,  
                       std::string const &driverFile) {  
        std::unique_ptr<DriverLoader> ret(  
            new DriverLoader(driverRoot, driverFile));  
        return ret;  
    }  

返回一个DriverLoader对象。

DriverLoader::DriverLoader(std::string const &driverRoot,  
                             std::string const &driverFile)  
      : impl_(new Impl),  
        logger_(osvr::util::log::make_logger("DriverLoader")) {  
      /// Set the PATH to include the driver directory so it can  
      /// find its deps.  
      SearchPathExtender extender(driverRoot);  
f defined(OSVR_WINDOWS)  
      impl_->driver_ = LoadLibraryA(driverFile.c_str());<strong><span style="font-size:14px;">// 加载steam目录下的driver_lighthouse.dll文件</span></strong>  
      if (!impl_->driver_) {  
          reset();  
          throw CouldNotLoadDriverModule();  
      }  
  
      auto proc = GetProcAddress(impl_->driver_, ENTRY_POINT_FUNCTION_NAME);<strong><span style="font-size:14px;">// 获取dll文件中的HmdDriverFactory接口地址</span></strong>  
      if (!proc) {  
          reset();  
          throw CouldNotLoadEntryPoint();  
      }  
      factory_ = reinterpret_cast<DriverFactory>(proc);<strong><span style="font-size:14px;">// 强制转换为void *(*)(const char *, int *)类型</span></strong>  
lif defined(OSVR_LINUX) || defined(OSVR_MACOSX)  
      impl_->driver_ = dlopen(driverFile.c_str(), RTLD_NOW | RTLD_GLOBAL);  
      if (!impl_->driver_) {  
          reset();  
          throw CouldNotLoadDriverModule(dlerror());  
      }  
  
      auto proc = dlsym(impl_->driver_, ENTRY_POINT_FUNCTION_NAME);  
      if (!proc) {  
          reset();  
          throw CouldNotLoadEntryPoint(dlerror());  
      }  
      factory_ = reinterpret_cast<DriverFactory>(proc);  
ndif  
  } 
static const auto ENTRY_POINT_FUNCTION_NAME = "HmdDriverFactory";

using DriverFactory = void *(*)(const char *, int *);
目的是存储一个地址到变量:factory_
在driver_lighthouse.dll中的vr::IServerTrackedDeviceProvider已提供接口如下:
CServerDriver g_ServerTrackedDeviceProvider;

HMD_DLL_EXPORT  
void *HmdDriverFactory(const char *pInterfaceName, int *pReturnCode)  
{  
    if (0 == strcmp(IServerTrackedDeviceProvider_Version, pInterfaceName)) {  
        return &g_ServerTrackedDeviceProvider;  
    }  
  
    if (pReturnCode) {  
        *pReturnCode = VRInitError_Init_InterfaceNotFound;  
    }  
  
    return NULL;  
}  

回到ViveDriverHost::start中,checkServerDeviceProviderInterfaces检测驱动需要的接口openvr_driver.h是否支持。

enum class InterfaceVersionStatus {  
           /// All mentioned interface version strings are handled/described by  
           /// the header we've built against.  
           AllInterfacesOK,// 驱动请求使用的所有接口类 openvr_driver.h中都支持  
           /// Not all mentioned interface version strings are  
           /// handled/described by the header we've built against, but the  
           /// interfaces that we use match.  
           AllUsedInterfacesOK, // 不是所有请求的接口类openvr_driver.h中都支持,但是所使用到的类都支持。  
           /// At least one of the interfaces that we use doesn't match the  
           /// version we built against.  
           InterfaceMismatch //至少一个所使用到的接口类在openvr_driver.h中不支持  
       };  
  
       static const char * const k_InterfaceVersions[] =  
   {  
       IVRSettings_Version,  
       ITrackedDeviceServerDriver_Version,  
       IVRDisplayComponent_Version,  
       IVRDriverDirectModeComponent_Version,  
       IVRControllerComponent_Version,  
       IVRCameraComponent_Version,  
       IServerTrackedDeviceProvider_Version,  
       IVRWatchdogProvider_Version,  
       IVRVirtualDisplay_Version,  
       nullptr  
   };  

serverDevProvider().GetInterfaceVersions()返回的是以上openvr_driver.h中的接口类名,并比较是否所有接口类版本都支持。
若一个版本不支持,则将其入队,并将其与本驱动care的版本进行对比,若是必须要使用的但是又不被openvr_driver.h所支持。
则allUsedSupported=false.

/// A list of just the interface names we actually use.  
        static const auto interfaceNamesWeCareAbout = {  
            "ITrackedDeviceServerDriver", "IVRDisplayComponent",  
            "IVRControllerComponent", //< @todo do we actually use/cast to  
                                      // this interface?  
            "IServerTrackedDeviceProvider", "IVRWatchdogProvider"};  

关于数据传输部分:
在driver_lighthouse.dll中通过RunFrame()中的vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_unObjectId, GetPose(), sizeof(DriverPose_t));
往vive中的以下接口发:

void ViveDriverHost::TrackedDevicePoseUpdated(uint32_t unWhichDevice,  
                                                  const DriverPose_t &newPose,  
                                                  uint32_t unPoseStructSize) {  
        submitTrackingReport(unWhichDevice, osvr::util::time::getNow(),  
                             newPose);  
    }  
  
void ViveDriverHost::submitTrackingReport(uint32_t unWhichDevice,  
                                              OSVR_TimeValue const &tv,  
                                              const DriverPose_t &newPose) {  
        TrackingReport out;  
        out.timestamp = tv;  
        out.sensor = unWhichDevice;  
        out.report = newPose;  
        {  
            std::lock_guard<std::mutex> lock(m_mutex);  
            m_trackingReports.submitNew(std::move(out), lock);  
        }  
    }  
因此,整个数据过程为:
通过DriverLoader.cpp加载dll后,再通过m_vive->startServerDeviceProvider()获取dll实现的
vr::IServerTrackedDeviceProvider接口, update中通过调用m_vive->serverDevProvider().RunFrame()结构,通过submitNew往deque_中push,vive osvr端通过grabItems到vector_。最后在update中再通过accessWorkItems获取

vector_。最终通过convertAndSendTracker中的osvrDeviceTrackerSendPoseTimestamped往应用程序传数据。其中chaperone
配置文件中的数据在handleUniverseChange中被处理。

2017-6-27------------------------------------------------------------------------


无论是在直连或者扩展模式上,HTC Vive和它的控制器被OSVR所支持且可以在任何OSVR应用程序上使用,还支持畸变校正,全方位追踪以及输入支持。

通过OSVR,OSVR-Vive插件及其工具访问Vive硬件。


兼容性:

然后改驱动应该兼容所有的Vive家族设备,到目前为止,它只在HTC Vive和Vive PRE(非早期开发版本)上测试过。

OSVR-Vive驱动与为Vive服务的SteamVR驱动交互(driver_lighthouse),因此与SteamVR版本也有关联。


安装流程:

首先确保Vive在SteamVR上工作正常且已经安排了一个房间,最好是进行一个站立状态或房间级别的校准作为游戏空间。然后,下载

与OSVR服务相对应位数的插件二进制包。

在下载的解压包内有以下文件:

1>.一个插件文件。在Windows上,这是一个在bin/osvr-plugins-0目录下的.dll文件。将它放在OSVR server相同目录下。

2>.在bin目录内,一个ViveDisplayExtractor工具---拷贝到OSVR server的bin目录下。

3>.一个起始样例配置文件osvr_server_config(还有一些可以快速替换的预设显示描述符以及网格文件)


首先应该在不需要改变任何SteamVR设置的基础上,能够以直连模式在Vive头显上运行一个OSVR的应用程序。如果Vive在SteamVR上以

直联模式工作正常,但是在OSVR上不能以直连模式打开,则原因可能是在OSVR应用程序启动之前SteamVR没有退出(需要确保在

OSVR应用程序启动之前SteamVR已经退出)。在一些系统上,退出SteamVR之前,在SteamVR菜单内可能需要禁止直连模式。


一次安装:Vive需要一个客户显示描述以及网格畸变数据文件,使用ViveDisplayExtractor工具提取这些文件数据。确保ViveDisplayExtractor与

osvr_server一起运行,也就是Vive与PC连接,SteamVR已经退出,运行ViveDisplayExtractor。


如果成功,将会看到类似以下:

[DisplayExtractor] Writing distortion mesh data file:
C:/Users/Ryan/Desktop/OSVR/bin/displays/HTC_Vive_PRE_meshdata.json

[DisplayExtractor] Writing display descriptor file:
C:/Users/Ryan/Desktop/OSVR/bin/displays/HTC_Vive_PRE.json

[DisplayExtractor] Press enter to quit...


Note:结果配置包含一个到网格数据的绝对路径,因此如果改变了osvr server所在目录,只需要再次运行ViveDisplayExtractor。

以上就是所有的了!现在可以使用样例osvr_server_config.vive.sample.json  文件作为服务配置文件了(将它改为默认名: osvr_server_config.json

),可以在Vive上运行OSVR启动的应用程序了。

如果想要运行SteamVR APP,没问题:只要关闭OSVR Server并且任何在直连模式运行的OSVR Apps即可。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值