227 lines
6.9 KiB
C++

////======================================================================================================
//// Copyright 2023, NaturalPoint Inc.
////======================================================================================================
/**
* ExampleGloveAdapterSingleton class is an adapter class provided to demonstrate how communication between plugin device and
* the glove SDK can be managed. A singleton instance of this class manages interaction between plugin device and the glove
* device SDK. The adapter instance also stores a keeps the latest data and device info map that stores the currently detected device serials
* and the latest frame data so that corresponding glove device can poll from it. Please note that this is provided only as an example, and
* there could be other ways to set this up.
*/
#pragma once
#include <list>
#include <mutex>
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <functional>
// OptiTrack Peripheral Device API
#include "AnalogChannelDescriptor.h"
#include "GloveDataFormat.h"
#include "HardwareSimulator.h"
// Rokoko Integration
#include "RokokoData.h"
#include "RokokoUDPReceiver.h"
#include "RokokoDataParser.h"
#include "RokokoDataConverter.h"
namespace OptiTrackPluginDevices
{
namespace ExampleDevice
{
class ExampleGloveAdapterSingleton;
static ExampleGloveAdapterSingleton* s_Instance = nullptr;
static std::unique_ptr<ExampleGloveAdapterSingleton> gGloveAdapter;
/**
* This is an example glove adapter (singleton) class provided to demonstrate how glove data can be populated.
* This adapter class is reponsible for all interaction with the device SDK, and populating the glove data.
* Glove data for multiple glove devices should get aggregated in here.
*/
class ExampleGloveAdapterSingleton
{
friend class ExampleGloveDevice;
public:
ExampleGloveAdapterSingleton(AnalogSystem::IDeviceManager* pDeviceManager);
~ExampleGloveAdapterSingleton();
// Singleton design pattern
ExampleGloveAdapterSingleton(const ExampleGloveAdapterSingleton&) = delete; // Should not be cloneable
ExampleGloveAdapterSingleton& operator=(const ExampleGloveAdapterSingleton& other) = delete; // Shounot be assignable
/**
* Should call the shutdown from the plugin SDK. In this case, shutsdown the simulator
*/
bool ClientShutdown();
/**
* Detection thread for connecting to the glove server.
*/
void DoDetectionThread();
std::thread mDetectionThread;
unsigned int mConnectionAttemptCount = 0;
const unsigned int kMaxConnectionAttempt = 10;
/**
* Connect to the glove host.
*/
bool ConnectToHost();
/**
* Connect to Rokoko Studio via UDP.
*/
bool ConnectToRokoko();
/**
* Disconnect from Rokoko Studio.
*/
void DisconnectFromRokoko();
private:
/**
* Returns whether detector is connected to Glove Host.
*/
bool IsConnected();
/**
* Saves the latest data to the map
*/
void SetLatestData(const sGloveDeviceData& gloveFingerData);
/**
* Pointer to device manager for additional operations
*/
void SetDeviceManager(AnalogSystem::IDeviceManager* pDeviceManager);
/**
* Saves the latest glove data to the map
*/
void SetLatestDeviceInfo(const sGloveDeviceBaseInfo& deviceInfo);
/**
* Gets the latest data for device with given unique serial
*/
bool GetLatestData(const std::uint64_t mDeviceSerial, sGloveDeviceData& gloveFingerData);
/**
* Creates new device by instantiating the factory and transferring it to Motive
*/
void CreateNewGloveDevice(sGloveDeviceBaseInfo& deviceInfo);
/**
* Prints error into Motive.
*/
void NotifyConnectionFail();
bool bIsConnected = false;
bool bIsDetecting = true;
int mCurrentDeviceIndex = 0;
std::string mServerAddress = "";
/**
* [Glove SDK Placeholder]
* Example data map for storing aggregated device data.
*/
uint16_t mDeviceCount = 0;
std::vector<uint64_t> mDetectedDevices;
std::unordered_map<uint64_t, sGloveDeviceData> mLatestGloveData;
std::unordered_map<uint64_t, sGloveDeviceBaseInfo> mLatestDeviceInfo;
/**
* Rokoko integration members
*/
std::unique_ptr<RokokoIntegration::RokokoUDPReceiver> mRokokoReceiver;
bool bIsRokokoConnected = false;
RokokoData::LiveFrame_v4 mLastRokokoFrame;
/**
* [Legacy Glove SDK Placeholder - Commented Out]
* The following methods were sample callback functions for simulated hardware.
* Now replaced by Rokoko UDP communication.
*/
// bool bIsSimulating;
void StartSimulatedHardware(int deviceCount); // Legacy support
static void RegisterSDKCallbacks(); // Legacy support
static void OnDataCallback(std::vector<SimulatedPluginDevices::SimulatedGloveFrameData>& gloveFingerData); // Legacy support
static void OnDeviceInfoCallback(std::vector<SimulatedPluginDevices::SimulatedDeviceInfo>& newGloveInfo); // Legacy support
static sGloveDeviceBaseInfo ConvertDeviceInfoFormat(SimulatedPluginDevices::SimulatedDeviceInfo& glove); // Legacy support
static sGloveDeviceData ConvertDataFormat(const SimulatedPluginDevices::SimulatedGloveFrameData& glove); // Legacy support
/**
* Rokoko UDP data callback function.
*/
void OnRokokoDataReceived(const std::vector<uint8_t>& data, const std::string& senderIP);
/**
* Process received Rokoko data and convert to OptiTrack format.
*/
void ProcessRokokoData(const std::vector<uint8_t>& data);
/**
* Update device information (battery, signal strength, etc.)
*/
void UpdateDeviceInfo(uint64_t deviceId);
/**
* Detect and create Rokoko devices dynamically
*/
void DetectAndCreateRokokoDevices();
/**
* Process data for multiple devices (left/right hand)
*/
void ProcessMultipleDeviceData(const RokokoData::LiveFrame_v4& rokokoFrame);
/**
* Process hand data for a specific device
*/
bool ProcessHandData(const RokokoData::Body& body, uint64_t deviceId, eGloveHandSide handSide);
/**
* Map left hand joints from Rokoko data
*/
void MapLeftHandJoints(const RokokoData::Body& body, std::vector<sFingerNode>& nodes);
/**
* Map right hand joints from Rokoko data
*/
void MapRightHandJoints(const RokokoData::Body& body, std::vector<sFingerNode>& nodes);
/**
* Map individual joint data
*/
void MapJoint(const RokokoData::ActorJointFrame& rokokoJoint, sFingerNode& optiTrackNode);
protected:
/**
* [Legacy Glove SDK Simulator - Commented Out]
* Instance of simulator (now replaced by Rokoko integration)
*/
// SimulatedPluginDevices::HardwareSimulator* mGloveSimulator;
/**
* [Glove SDK Placeholder]
* Example glove data mutex
*/
std::recursive_mutex* mGloveDataMutex;
/**
* Pointer to device manager in Motive for reporting error messages.
*/
AnalogSystem::IDeviceManager* mDeviceManager;
};
}
}