//====================================================================================================== // Copyright 2016, NaturalPoint Inc. //====================================================================================================== #pragma once // STL // Private STL members are OK in exported class since they do not cross the DLL boundary #pragma warning( push ) #pragma warning( disable : 4251 ) #pragma warning( disable : 4275 ) #include #include #include #include #include #include // OptiTrack PluginDevice API #include "AnalogSystemBuildConfig.h" #include "IDevice.h" #include "AnalogFrame.h" #include "AnalogChannelDescriptor.h" #include "PropertySet.h" #define ANALOG_DEVICEBUFFERSIZE 1000 #define ANALOG_ERRORMESSAGESIZE 4096 #define ANALOG_MAXSAMPLESPERMOCAPFRAME 16 namespace MoCapCore { class cPropertyCollectionDefinition; } namespace AnalogSystem { class AnalogChannelDescriptor; class IDeviceManager; class AnalogFrameGroup; /// /// Device sync mode /// enum DeviceSyncMode { DeviceSync_FreeRun = 0, // Free running DeviceSync_Triggered // Waits for a trigger signal in data packet before starting }; /// /// Device Type (Devices can register themselves as a known type (e.g. Force Plate) /// which can help Motive in interpreting the device in the UI, used derived node classes, etc. /// enum DeviceType { DeviceType_None = 0, // No particular type DeviceType_NIDAQ, // NIDAQ card DeviceType_ForcePlate, // Force plate DeviceType_EyeTracker, // Eye Tracker DeviceType_Pointer, // Pointer DeviceType_Glove // Glove }; /// /// Frame Flags /// enum FrameFlag { FrameFlag_SyncBit = 0x01, // this frame contained a sync bit from the device FrameFlag_DropFrame = 0x02, // this frame was dropped by the device and is padded with 0's FrameFlag_Synthetic = 0x04 // this frame contains synthetic (padded or device filled) data }; /// /// Device frame buffer state /// enum DeviceBufferState { Buffer_Ready = 0, Buffer_NeedSync = -1, Buffer_Behind = -2, Buffer_Ahead = -3, Buffer_Empty = -4, Buffer_MocapFrameOutOfRange = -5 }; /// /// Device data state (not ready, ready, data flowing) /// enum DeviceDataState { DeviceState_NotReady = 0, // Device not ready (channels not configured, not calibrated, etc) DeviceState_Ready, // Device ready for capture (channels enabled and correctly configured, calibrated, etc) DeviceState_ReceivingData // Device actually actively receiving data }; /// /// Device sync state /// enum DeviceSyncStatus { DeviceSyncStatus_NeedSync = 0, DeviceSyncStatus_Resyncing, DeviceSyncStatus_ReadyForSync, DeviceSyncStatus_Synced }; /// /// cPluginDeviceBase is the base implementation class for a Motive Plugin Device/ /// /// Implementors should derive from the template PluginDevice subclass // /// A PluginDevice provides /// - Device operation callbacks, to be overridden by device implementor /// - Device channel and property management, for exposing device channel information /// and custom properties to the Motive UI. Also provides property change event /// communication between Motive and Device /// - Data management, providing a thread-safe user-typed data buffer for the device to /// quickly write to, and for Motive to read from. /// /// class ANALOGSYSTEM_API cPluginDeviceBase : public IDevice, public cPropertySet { public: cPluginDeviceBase(); virtual ~cPluginDeviceBase(); /////////////////////////////////////////////////////////////////////// // // Plugin Device Interface (override in derived plugin device) // ///Perform device specific configuration, allocates channel buffer. (Call base when implementing) bool Configure() override; /// Deconfigure this instance bool Deconfigure() override; /// Zero the device void Zero() override; /// Prepare live clocked devices for sync bool PrepareForSync() override; /// Perform any device-specific pre-capture operations bool PreCapture() override; /// Start device sampling (Call base when implementing) bool StartCapture() override; /// Stop device sampling (Call base when implementing) bool StopCapture() override; /// Perform any device-specific post-capture operations bool PostCapture() override; /// Return whether device is actively capturing data bool IsCapturing() const override; /// Return whether device is actively capturing data bool IsReady() const; /// Gives device a chance to validate a property value before applying it bool ValidatePropertyChange( const char* propertyName, const IPropVal& val ) override; /// Handle device specific property change events void OnPropertyChanged( const char* propertyName ) override; /// Handle device channel property change events void OnChannelPropertyChanged( const char* channelName, const char* propertyName ) override; /// Generic device-defined message passed from host (e.g. Motive) to device int MessageFromHost( const char* ) const override; /////////////////////////////////////////////////////////////////////// // // Plugin Device Base Implementation (do not override) // // channels /// Retrieves the ChannelDescriptor at the specified index AnalogChannelDescriptor* ChannelDescriptor( int index ) override; /// Retrieves the ChannelDescriptor at the specified channel name AnalogChannelDescriptor* ChannelDescriptor( const char* channelName ) override; /// Retrieves the number of Channels int ChannelDescriptorCount() const override; /// Retrieves the number of enabled channels int ActiveChannelCount() const override; /// Retrieves the ChannelDescriptor at the specified active channel index AnalogChannelDescriptor* ActiveChannelDescriptor( int index ) override; /// Retrieves the ChannelID at the specified index int ChannelID( int index ) const override; /// Retrieves the ChannelID associated with the specified channel name int ChannelID( const char* channelName ) const; // data /// Called by Device before updating the frame buffer to lock the buffer and provide a slot /// The device frame ID. /// Slot to write data to AnalogFrameBase* BeginFrameUpdate( long DeviceFrameID, bool wait = true ) override; /// Called by device when frame update is done, unlocking the buffer and updating the indexer void EndFrameUpdate() override; /// Gets a frame of data from the device buffer at the specified buffer index const AnalogFrameBase* GetFrameByBufferIndex( int index ) const override; /// Gets a frame of data from the device buffer at the specified frame ID const AnalogFrameBase* GetFrameByDeviceFrameID( long frameID ) const override; /// Gets a newly allocated mocap aligned group of device frames. Caller is responsible for relasing framegroup /// The mocap frame ID /// 0 if successful, error code otherwise /// Collection of analog frames AnalogFrameGroup* GetFrameGroupByMocapFrameID( long mocapFrameID, DeviceBufferState& resultCode, bool recording = false ); /// Gets a mocap aligned frame group /// caller provided frame group /// The mocap frame ID /// 0 if successful, error code otherwise DeviceBufferState GetFrameGroupByMocapFrameID( AnalogFrameGroup& frameGroup, long mocapFrameID, bool recording = false ); /// Gets the buffer index of the most recently added frame int GetMostRecentFrameIndex() const override; /// Gets the frame ID of the most recently added frame long GetMostRecentFrameID() const override; /// Gets the frame ID of the oldest frame in the buffer long GetOldestFrameID(); /// Updates the software drift correction based on the most recent mocap and device frames /// Most recent mocap frame ID void UpdateDriftCorrection( long mocapFrameID ) override; /// Resets the drift correction void ResetDriftCorrection(); /// Resets all sync counters (frame id, timestamp) void ResetSyncCounters(); /// Gets the most recent Frame ID long FrameCounter() const; /// Sets the most recent Frame ID void SetFrameCounter( long val ); /// Sets the DeviceManager (Device to Motive communication interface) void SetDeviceManager( IDeviceManager* pDeviceManager ) override; /// Gets the DeviceManager IDeviceManager* DeviceManager() override; /// Logs an error message void LogError( int errorType, const char* fmt, ... ); /// Gets the last logged error message const char* LastError() const override; /// Gets the size (in bytes) of a channel int DataSize() const; /// Returns the number of device frame sampled per mocap frame int DeviceFramesPerMocapFrame() const; /// Return the sync aligned device frame IDs for the specified mocap frame ID /// Mocap frame /// Device frame start /// Device frame stop /// true if successful, false otherwise bool MocapFrameIDToDeviceFrameIDs( long requestedMocapFrameID, long& deviceStart, long& deviceStop ) const override; bool HaveSyncFrames() const; void UpdateDeviceSyncStatus(); uint64_t LastArrivedSampleTimestamp() const; // IProfileSubscriber Interface std::wstring ProfileTypeName() const override; std::wstring ProfileLabel() const override; std::wstring ProfileDescription() const override; void SaveToProfile( tinyxml2wc::XMLElement& saveTo ) const override; bool LoadFromProfile( const tinyxml2wc::XMLElement& source ) override; // deprecated void AddFrameToBuffer( AnalogFrameBase* pFrame ); virtual void RegisterFactory( int channelCount ) { }; // PluginDevice Standard Properties. Plugins can add UI exposed custom properties via AddProperty() static const char* kEnabledPropName; static const char* kNamePropName; static const char* kDisplayNamePropName; static const char* kModelPropName; static const char* kSerialPropName; static const char* kChannelCountPropName; static const char* kRatePropName; static const char* kMocapRateMultiplePropName; static const char* kUseExternalClockPropName; static const char* kDeviceTypePropName; static const char* kExternalClockTerminalPropName; static const char* kExternalTriggerTerminalPropName; static const char* kOrderPropName; static const char* kMocapRatePropName; static const char* kSyncStatusPropName; static const char* kSyncModePropName; static const char* kMocapSyncFramePropName; static const char* kSyncFramePropName; static const char* kNeedDeviceSyncFramePropName; static const char* kNeedMocapSyncFramePropName; static const char* kDriftCorrectionPropName; static const char* kUseDriftCorrectionPropName; static const char* kExternalClockChannelPropName; static const char* kMasterSerialPropName; static const char* kSlaveIndexPropName; static const char* kNoiseAveragePropName; static const char* kZeroPropName; static const char* kDataStatePropName; static const char* kAppRunModePropName; static const char* kGroupNamePropName; static const char* kAssetPropName; static const char* kConnectedPropName; static const char* kDummySerialPropName; static const char* kUserDataPropName; static const char* kCorner0PropName; static const char* kCorner1PropName; static const char* kCorner2PropName; static const char* kCorner3PropName; static const char* kScalePropName; static const char* kCalOffsetPropName; static const char* kCalSquareRotationPropName; protected: /// Adds a channel definition to the device /// Name of the channel. /// Type of the data. /// ID of the new channel int AddChannelDescriptor( char* channelName, int dataType = (int) ChannelType_Float ); // allocate a new frame (implemented in derived template class) virtual AnalogFrameBase* AllocateFrame( int channelCount ) = 0; /// Size (in bytes) of a data channel int mDataSize; bool mIsReady; bool mIsCapturing; long mRecordingDeviceSyncFrame = -1; long mLiveDeviceSyncFrame = -1; private: // properties std::shared_ptr CreatePropertyDefinitions(); // channels std::vector mChannelDescriptors; std::vector mActiveChannelMap; // data AnalogFrameBase* GetNextSlot( long DeviceFrameID ); bool LockBuffer( bool wait = true ) const; void UnlockBuffer() const; void ReleaseBuffer(); std::vector mFrameBuffer; mutable void* mFrameBufferLock; int mFrameBufferSize; int mLastAddedIndex; std::map mAnalogFrameIDToBufferIndex; long mFrameCounter; long mDriftCorrection; // helpers IDeviceManager* mDeviceManager; char mLastErrorMsg[ANALOG_ERRORMESSAGESIZE]; void* mMessageLock; std::wstring mDeviceName; static const std::wstring kPropertyDefinitionName; static Core::cUID sPropertyDefinitionsID; std::chrono::time_point mLastTimestamp; bool mCached_NeedDeviceSyncFrame = true; }; } #pragma warning( pop )