//====================================================================================================== // Copyright 2023, NaturalPoint Inc. //====================================================================================================== /** * GloveDeviceBase/GloveDeviceFactory class extends the cPluginDeviceBase and configures data channels and device properties required * by a glove device in Motive. The purpose of this class is to abstract out setups needed for creating glove device as demonstrated * in the ExampleGloveDevice. When developing a glove plugin to animate fingers in Motive, the following class can be inherited if needed. */ #include #include #include #include // OptiTrack Peripheral Device API #include "PluginDevice.h" #include "PluginDeviceFactory.h" #include "GloveDataFormat.h" namespace OptiTrackPluginDevices { class GloveDeviceBase; class GloveDeviceFactoryBase; /** * Common glove device properties used in Motive. */ namespace GloveDeviceProperties { static const int kHandSideCount = 3; static const char* GloveHandSide[kHandSideCount] = { "Uninitialized", "Left", "Right" }; // Glove type needs to be set at the device level (0 = uninitialized, 1 = left, 2 = right) static const char* GloveDeviceProp_HandSide = "Hand Side"; static const char* GloveDeviceProp_Battery = "Battery"; static const char* GloveDeviceProp_SignalStrength = "Signal Strength"; static const char* GloveDeviceProp_ServerAddress = "Server Address"; static const char* GloveDeviceProp_Reconnect = "Reconnect"; static const char* GloveDeviceProp_Solver = "Glove Solver"; static const int GloveDeviceProp_BatteryUninitialized = -1; static const int GloveDeviceProp_SignalStrengthUnitialized = -1; static const int kGloveAnalogChannelCount = 60; } /** * GloveDeviceFactory class demonstrates how plugin device factory can be set up for creating a glove device in Motive. * To create a device in Motive, an instance of PLuginDeviceFactory must be created per each device, and then, its ownership must be * transferred to Motive by using Create method. The GloveDeviceFactory inherits from PLuginDeviceFactory and demonstrates common * glove properties and data channels can be configured; which is demonstrated in this base class. */ class GloveDeviceFactoryBase : public AnalogSystem::PluginDeviceFactory { public: GloveDeviceFactoryBase(std::string deviceName, uint32_t serial) : AnalogSystem::PluginDeviceFactory(deviceName.c_str()), mDeviceSerial(serial) {} uint32_t mDeviceSerial = -1; int mDeviceIndex = 0; protected: void SetDeviceIndex(int t_index); /** * Sets up quaternion data channels for delivering local rotation of the finger nodes. * Motive skeleton's hand consists of total 15 finger nodes, 3 per each finger. * These data channels will get populated by the collection thread running on each device. * Quaternion values are expected, resulting in total 60 float channels (15 finger nodes * 4 quat floats / node). * Local rotation data is expected, and both hand data expects right-handed coordinate system with +x axis * pointing towards the finger tip for left hand and towards the wrist/body for right hand. */ void SetQuaternionDataChannels(GloveDeviceBase* pDevice) const; /** * Set Common Glove device properties */ void SetCommonGloveDeviceProperties(GloveDeviceBase* pDevice) const; }; /** * cGloveDeviceBase class is an example class which glove devices could inherit from. * This class includes basic setups and configurations for glove devices in Motive. */ class GloveDeviceBase : public AnalogSystem::cPluginDevice { friend class GloveDeviceFactoryBase; public: GloveDeviceBase(); ~GloveDeviceBase() = default; void SetCommonDeviceProperties(); void SetCommonGloveDeviceProperties(); protected: // Device status bool bIsEnabled = false; bool bIsCollecting = false; bool bIsInitialized = false; bool bIsConfigured = false; // Device info sGloveDeviceBaseInfo mGloveInfo; std::string mDeviceSerial = ""; eGloveHandSide mHandSide = eGloveHandSide::Unknown; int mBatteryLevel = 0; int mSignalStrength = 0; double mDeviceRateFPS = 0; double mRequestedRateMS = 0.0; // Glove data sGloveDeviceData mLastGloveData; // Collection thread must be created on the device class. Defined in ExampleGloveDevice class. virtual unsigned long DoCollectionThread() = 0; /** * Configure device rate */ void SetDeviceRate(int rate); /** * Configure hand side */ void SetHandSide(eGloveHandSide side); /** * Enable or disable device */ void SetEnabled(bool enabled); /** * Set collection status */ void SetCollecting(bool collecting); /** * Set device serial string each device must have unique serial */ bool SetDeviceSerial(std::string serial); /** * Set device data */ bool SetDeviceData(sGloveDeviceData data); /** * Set device battery level (1-100) */ bool SetBatteryLevel(int level); /** * Sets the signal stregth (1-128) */ bool SetSignalStrength(int signal); bool IsEnabled() { return bIsEnabled; }; bool IsCollecting() { return bIsCollecting; }; int GetSignalStrength() { return mSignalStrength; } int GetBatteryLevel() { return mBatteryLevel; } double GetDeviceRate() { return mDeviceRateFPS; } sGloveDeviceData GetLastestData() { return mLastGloveData; }; /** * Initialize the properties for the glove device */ void InitializeGloveProperty(); /** * Updates the device properties. Gets called periodically within collection thread. * Mainly updates the battery level and signal strength. */ void UpdateGloveProperty(const sGloveDeviceBaseInfo& deviceInfo); sGloveDeviceBaseInfo mDeviceInfo; }; }