181 lines
5.8 KiB
C++

//======================================================================================================
// 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 <memory>
#include <list>
#include <mutex>
#include <thread>
// 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<float>
{
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;
};
}