init
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
PROJECT(openvibe-plugins-vrpn)
|
||||
|
||||
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
|
||||
SET(PROJECT_VERSION ${OV_GLOBAL_VERSION_STRING})
|
||||
|
||||
INCLUDE("FindThirdPartyVRPN_Check")
|
||||
IF(NOT PATH_VRPN)
|
||||
MESSAGE(STATUS " --> Not building ${PROJECT_NAME}")
|
||||
RETURN()
|
||||
ENDIF(NOT PATH_VRPN)
|
||||
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.inl)
|
||||
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
FOLDER ${PLUGINS_FOLDER}
|
||||
COMPILE_FLAGS "-DOVP_Exports -DOVP_Shared")
|
||||
|
||||
# ---------------------------------
|
||||
INCLUDE("FindOpenViBE")
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
INCLUDE("FindOpenViBEToolkit")
|
||||
INCLUDE("FindOpenViBEModuleEBML")
|
||||
INCLUDE("FindOpenViBEModuleSocket")
|
||||
INCLUDE("FindThirdPartyVRPN")
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* \page BoxAlgorithm_AnalogVRPNServer Analog VRPN server
|
||||
__________________________________________________________________
|
||||
|
||||
Detailed description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_AnalogVRPNServer_Description|
|
||||
*
|
||||
* This plugin exposes several \ref Doc_Streams_StreamedMatrix streams
|
||||
* to an external application thanks to the \e VRPN protocol. \e VRPN stands
|
||||
* for Virtual Reality Peripheral Network (http://www.cs.unc.edu/Research/vrpn/).
|
||||
* It consists in a library that abstracts most used VR peripherals as
|
||||
* an aggregation of basic components such as \e analogic data, \e buttons
|
||||
* or \e trackers (localisation and orientation in space).
|
||||
*
|
||||
* The way §OpenViBE§ exposes \ref Doc_Streams_StreamedMatrix streams to
|
||||
* external applications consists in emulating an multi-channel analogic
|
||||
* device. The number of elements contained in the buffers of the stream
|
||||
* will fix the number of channels of the emulated device. Given this
|
||||
* behavior, any \e VRPN ready application is able to get parameters
|
||||
* from §OpenViBE§ and to provide feedback to the user as visual information
|
||||
* or whatever way the feedback should be done.
|
||||
*
|
||||
* |OVP_DocEnd_BoxAlgorithm_AnalogVRPNServer_Description|
|
||||
__________________________________________________________________
|
||||
|
||||
Inputs description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_AnalogVRPNServer_Inputs|
|
||||
* This box accepts unlimited number of inputs. Initial box only
|
||||
* has a single input but you can add as many \ref Doc_Streams_StreamedMatrix
|
||||
* derived inputs as you want to the box.
|
||||
*
|
||||
* Note that in case you add inputs, the total number of channels
|
||||
* of the emulated device will be the sum of the number of elements
|
||||
* of each buffer.
|
||||
* |OVP_DocEnd_BoxAlgorithm_AnalogVRPNServer_Inputs|
|
||||
*
|
||||
* |OVP_DocBegin_BoxAlgorithm_AnalogVRPNServer_Input1|
|
||||
* This input will receive the matrices from preceding boxes and
|
||||
* update the multi-analog device according to the matrix buffer.
|
||||
* |OVP_DocEnd_BoxAlgorithm_AnalogVRPNServer_Input1|
|
||||
__________________________________________________________________
|
||||
|
||||
Settings description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_AnalogVRPNServer_Settings|
|
||||
* |OVP_DocEnd_BoxAlgorithm_AnalogVRPNServer_Settings|
|
||||
*
|
||||
* |OVP_DocBegin_BoxAlgorithm_AnalogVRPNServer_Setting1|
|
||||
* This setting contains the name of the emulated peripheral. This will be used
|
||||
* by the external application in order to connect to this peripheral. If this
|
||||
* setting is \e openvibe-vrpn and the machine running §OpenViBE§ is
|
||||
* \e openvibe-machine, then the complete \e VRPN peripheral name is
|
||||
* \e openvibe-vrpn\@\e openvibe-machine.
|
||||
* |OVP_DocEnd_BoxAlgorithm_AnalogVRPNServer_Setting1|
|
||||
__________________________________________________________________
|
||||
|
||||
Examples description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_AnalogVRPNServer_Examples|
|
||||
* |OVP_DocEnd_BoxAlgorithm_AnalogVRPNServer_Examples|
|
||||
__________________________________________________________________
|
||||
|
||||
Miscellaneous description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_AnalogVRPNServer_Miscellaneous|
|
||||
* This box lacks an additional setting to specify the connection port.
|
||||
* Default \e VRPN connection port is \c 3883. But it may be possible that
|
||||
* you want to expose §OpenViBE§ on another port. This is not currently possible.
|
||||
*
|
||||
* Note that if the box receives no input header or data, the clients
|
||||
* will see a channel count of 0 until header has been processed by the box.
|
||||
*
|
||||
* For \e buttons emulation, you way want to look at the
|
||||
* \ref Doc_BoxAlgorithm_ButtonVRPNServer documentation that does almost
|
||||
* the same as this box but transcoding stimulations to button states.
|
||||
* |OVP_DocEnd_BoxAlgorithm_AnalogVRPNServer_Miscellaneous|
|
||||
*/
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* \page BoxAlgorithm_ButtonVRPNServer Button VRPN server
|
||||
__________________________________________________________________
|
||||
|
||||
Detailed description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Description|
|
||||
*
|
||||
* This plugin exposes several boolean states
|
||||
* to an external application thanks to the \e VRPN protocol. \e VRPN stands
|
||||
* for Virtual Reality Peripheral Network (http://www.cs.unc.edu/Research/vrpn/).
|
||||
* It consists in a library that abstracts most used VR peripherals as
|
||||
* an aggregation of basic components such as \e analogic data, \e buttons
|
||||
* or \e trackers (localisation and orientation in space).
|
||||
*
|
||||
* The way §OpenViBE§ exposes these boolean states to
|
||||
* external applications consists in emulating a multi-button
|
||||
* device. The states are controled by stimulation streams and each
|
||||
* button can be pressed and released by given stimulation identifiers.
|
||||
* The number of buttons of the emulated device depends on the number
|
||||
* of input of the box. Each time an input is added, the corresponding
|
||||
* on/off stimulations are added to the settings of the box. Given this
|
||||
* behavior, any \e VRPN ready application is able to get parameters
|
||||
* from §OpenViBE§ and to provide feedback to the user as visual information
|
||||
* or whatever way the feedback should be done.
|
||||
*
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Description|
|
||||
__________________________________________________________________
|
||||
|
||||
Inputs description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Inputs|
|
||||
* This box accepts unlimited number of inputs. Initial box only
|
||||
* has a single input but you can add as many \ref Doc_Streams_Stimulation
|
||||
* inputs as you want to the box.
|
||||
*
|
||||
* Note that in case you add inputs, the total number of button
|
||||
* of the emulated device will be the exact number of inputs, and
|
||||
* that the corresponding settings will be added automatically.
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Inputs|
|
||||
*
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Input1|
|
||||
* This input will receive a stimulation stream and change the corresponding
|
||||
* button state according to two stimulations.
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Input1|
|
||||
__________________________________________________________________
|
||||
|
||||
Settings description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Settings|
|
||||
* Each input have a corresponding pair of stimulation codes that are
|
||||
* used to press or release a button. When the first stimulation is
|
||||
* found, the button switches to sate \e pressed. When the second one
|
||||
* is found, the button switches to state \e released. In case the
|
||||
* first stimulation appears while the button is already \e pressed,
|
||||
* nothing happens. Similarly, when the second stimulation appears while
|
||||
* the button is already \e released, nothing happens.
|
||||
*
|
||||
* If the on and off stimulation codes for a given button are the same,
|
||||
* then when this stimulation happens, the button state switches to \e pressed
|
||||
* and immediately comes back to \e released. Client application will receive
|
||||
* the two state changes.
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Settings|
|
||||
*
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Setting1|
|
||||
* This setting contains the name of the emulated peripheral. This will be used
|
||||
* by the external application in order to connect to this peripheral. If this
|
||||
* setting is \e openvibe-vrpn and the machine running §OpenViBE§ is
|
||||
* \e openvibe-machine, then the complete \e VRPN peripheral name is
|
||||
* \e openvibe-vrpn\@\e openvibe-machine.
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Setting1|
|
||||
*
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Setting2|
|
||||
* This setting gives the stimulation code to track to switch button state to
|
||||
* \e pressed.
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Setting2|
|
||||
*
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Setting3|
|
||||
* This setting gives the stimulation code to track to switch button state to
|
||||
* \e released.
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Setting3|
|
||||
__________________________________________________________________
|
||||
|
||||
Examples description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Examples|
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Examples|
|
||||
__________________________________________________________________
|
||||
|
||||
Miscellaneous description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithm_ButtonVRPNServer_Miscellaneous|
|
||||
* This box lacks an additional setting to specify the connection port.
|
||||
* Default \e VRPN connection port is \c 3883. But it may be possible that
|
||||
* you want to expose §OpenViBE§ on another port. This is not currently possible.
|
||||
*
|
||||
* For \e analogs emulation, you way want to look at the
|
||||
* \ref Doc_BoxAlgorithm_AnalogVRPNServer documentation that does almost
|
||||
* the same as this box but transcoding streamed matrices to analog states.
|
||||
* |OVP_DocEnd_BoxAlgorithm_ButtonVRPNServer_Miscellaneous|
|
||||
*/
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "ovpCBoxAlgorithmVRPNAnalogClient.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
|
||||
|
||||
static void VRPN_CALLBACK vrpn_analog_cb(void* data, const vrpn_ANALOGCB a)
|
||||
{
|
||||
CBoxAlgorithmVRPNAnalogClient* client = static_cast<CBoxAlgorithmVRPNAnalogClient*>(data);
|
||||
client->setAnalog(a.num_channel, a.channel);
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmVRPNAnalogClient::initialize()
|
||||
{
|
||||
m_vrpnAnalogRemote = nullptr;
|
||||
|
||||
m_peripheralName = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
m_sampling = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
|
||||
m_nChannel = uint64_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2));
|
||||
m_nSamplePerSentBlock = uint64_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3));
|
||||
|
||||
m_encoder = &this->getAlgorithmManager().getAlgorithm(this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_SignalEncoder));
|
||||
m_encoder->initialize();
|
||||
|
||||
ip_matrix.initialize(m_encoder->getInputParameter(OVP_GD_Algorithm_SignalEncoder_InputParameterId_Matrix));
|
||||
ip_sampling.initialize(m_encoder->getInputParameter(OVP_GD_Algorithm_SignalEncoder_InputParameterId_Sampling));
|
||||
op_buffer.initialize(m_encoder->getOutputParameter(OVP_GD_Algorithm_SignalEncoder_OutputParameterId_EncodedMemoryBuffer));
|
||||
|
||||
m_firstStart = true;
|
||||
m_lastChunkEndTime = 0;
|
||||
|
||||
m_chunkDuration = CTime(m_sampling, m_nSamplePerSentBlock).time();
|
||||
|
||||
m_lastSamples.resize(m_nChannel);
|
||||
m_sampleBuffer.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmVRPNAnalogClient::uninitialize()
|
||||
{
|
||||
if (m_vrpnAnalogRemote)
|
||||
{
|
||||
delete m_vrpnAnalogRemote;
|
||||
m_vrpnAnalogRemote = nullptr;
|
||||
}
|
||||
|
||||
if (m_encoder)
|
||||
{
|
||||
m_encoder->uninitialize();
|
||||
this->getAlgorithmManager().releaseAlgorithm(*m_encoder);
|
||||
m_encoder = nullptr;
|
||||
}
|
||||
|
||||
m_sampleBuffer.clear();
|
||||
m_lastSamples.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmVRPNAnalogClient::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmVRPNAnalogClient::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
|
||||
if (m_firstStart)
|
||||
{
|
||||
ip_sampling = m_sampling;
|
||||
ip_matrix->resize(m_nChannel, m_nSamplePerSentBlock);
|
||||
|
||||
// @TODO do labels ?
|
||||
|
||||
op_buffer = boxContext.getOutputChunk(0);
|
||||
m_encoder->process(OVP_GD_Algorithm_SignalEncoder_InputTriggerId_EncodeHeader);
|
||||
boxContext.markOutputAsReadyToSend(0, 0, 0);
|
||||
|
||||
m_lastSamples.resize(m_nChannel);
|
||||
for (size_t i = 0; i < m_nChannel; ++i) { m_lastSamples[i] = 0; }
|
||||
|
||||
m_firstStart = false;
|
||||
}
|
||||
|
||||
if (!m_vrpnAnalogRemote)
|
||||
{
|
||||
m_vrpnAnalogRemote = new vrpn_Analog_Remote(m_peripheralName.toASCIIString());
|
||||
m_vrpnAnalogRemote->register_change_handler(this, &vrpn_analog_cb);
|
||||
}
|
||||
|
||||
m_vrpnAnalogRemote->mainloop();
|
||||
|
||||
const uint64_t time = this->getPlayerContext().getCurrentTime();
|
||||
|
||||
if ((time - m_lastChunkEndTime) >= m_chunkDuration)
|
||||
{
|
||||
// Time to send a chunk. Copy our current sample buffer to the output matrix.
|
||||
size_t idx = 0;
|
||||
double* oBuffer = ip_matrix->getBuffer();
|
||||
|
||||
while (!m_sampleBuffer.empty())
|
||||
{
|
||||
const std::vector<double>& tmp = m_sampleBuffer.front();
|
||||
|
||||
for (size_t j = 0; j < m_nChannel; ++j) { oBuffer[j * m_nSamplePerSentBlock + idx] = tmp[j]; }
|
||||
|
||||
m_sampleBuffer.pop_front();
|
||||
idx++;
|
||||
}
|
||||
// If the buffer didn't have enough data from callbacks, pad with the last sample
|
||||
while (idx < m_nSamplePerSentBlock)
|
||||
{
|
||||
for (size_t j = 0; j < m_nChannel; ++j) { oBuffer[j * m_nSamplePerSentBlock + idx] = m_lastSamples[j]; }
|
||||
idx++;
|
||||
}
|
||||
|
||||
op_buffer = boxContext.getOutputChunk(0);
|
||||
m_encoder->process(OVP_GD_Algorithm_SignalEncoder_InputTriggerId_EncodeBuffer);
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastChunkEndTime, m_lastChunkEndTime + m_chunkDuration);
|
||||
m_lastChunkEndTime += m_chunkDuration;
|
||||
#if defined _DEBUG
|
||||
const double diff = CTime(m_lastChunkEndTime).toSeconds() - CTime(time).toSeconds();
|
||||
if (std::abs(diff) > 1) { this->getLogManager() << Kernel::LogLevel_Warning << "Time difference detected: " << diff << " secs.\n"; }
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBoxAlgorithmVRPNAnalogClient::setAnalog(const size_t nAnalog, const double* analog)
|
||||
{
|
||||
// Count how many samples are encoded in pAnalog
|
||||
const size_t nSample = nAnalog / m_nChannel;
|
||||
for (size_t i = 0; i < nSample; ++i)
|
||||
{
|
||||
// Append the sample to the buffer
|
||||
for (size_t j = 0; j < m_nChannel; ++j) { m_lastSamples[j] = analog[j * nSample + i]; }
|
||||
m_sampleBuffer.push_back(m_lastSamples);
|
||||
|
||||
// Drop the oldest sample if our buffer got full. This means that VRPN is sending data faster than we consume.
|
||||
if (m_sampleBuffer.size() > m_nSamplePerSentBlock) { m_sampleBuffer.pop_front(); }
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyVRPN
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
#include <vrpn_Analog.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
class CBoxAlgorithmVRPNAnalogClient final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { delete this; }
|
||||
|
||||
uint64_t getClockFrequency() override { return 128LL << 32; } // the box clock frequency
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_VRPNAnalogClient)
|
||||
|
||||
void setAnalog(size_t nAnalog, const double* analog);
|
||||
|
||||
protected:
|
||||
|
||||
uint64_t m_lastChunkEndTime = 0;
|
||||
uint64_t m_chunkDuration = 0;
|
||||
size_t m_sampling = 0;
|
||||
size_t m_nChannel = 0;
|
||||
size_t m_nSamplePerSentBlock = 0;
|
||||
|
||||
bool m_firstStart = false;
|
||||
|
||||
Kernel::IAlgorithmProxy* m_encoder = nullptr;
|
||||
Kernel::TParameterHandler<CMatrix*> ip_matrix;
|
||||
Kernel::TParameterHandler<uint64_t> ip_sampling;
|
||||
Kernel::TParameterHandler<IMemoryBuffer*> op_buffer;
|
||||
|
||||
CString m_peripheralName;
|
||||
|
||||
std::deque<std::vector<double>> m_sampleBuffer; // Used as a limited-size buffer of sample vectors
|
||||
std::vector<double> m_lastSamples; // The last sample received from VRPN
|
||||
|
||||
vrpn_Analog_Remote* m_vrpnAnalogRemote = nullptr;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmVRPNAnalogClientDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("Analog VRPN Client"); }
|
||||
CString getAuthorName() const override { return CString("Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("INRIA"); }
|
||||
|
||||
CString getShortDescription() const override
|
||||
{
|
||||
return CString("Connects to an external VRPN device and translate an analog information into OpenViBE signal");
|
||||
}
|
||||
|
||||
CString getDetailedDescription() const override { return CString("-"); }
|
||||
CString getCategory() const override { return CString("Acquisition and network IO/VRPN"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getStockItemName() const override { return CString("gtk-connect"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_VRPNAnalogClient; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmVRPNAnalogClient; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
// prototype.addInput ("input name", /* input type (OV_TypeId_Signal) */);
|
||||
prototype.addOutput("Output", OV_TypeId_Signal);
|
||||
prototype.addSetting("Peripheral name", OV_TypeId_String, "openvibe-vrpn@localhost");
|
||||
prototype.addSetting("Sampling Rate", OV_TypeId_Integer, "512");
|
||||
prototype.addSetting("Number of Channels", OV_TypeId_Integer, "16");
|
||||
prototype.addSetting("Sample Count per Sent Block", OV_TypeId_Integer, "32");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_VRPNAnalogClientDesc)
|
||||
};
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
#endif // TARGET_HAS_ThirdPartyVRPN
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "ovpCBoxAlgorithmVRPNButtonClient.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
|
||||
static void VRPN_CALLBACK vrpn_button_cb(void* data, const vrpn_BUTTONCB b)
|
||||
{
|
||||
CBoxAlgorithmVRPNButtonClient* box = static_cast<CBoxAlgorithmVRPNButtonClient*>(data);
|
||||
|
||||
(box->m_Buttons).push_back(std::pair<size_t, bool>(b.button, b.state ? true : false));
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmVRPNButtonClient::initialize()
|
||||
{
|
||||
const size_t nOutput = this->getStaticBoxContext().getOutputCount();
|
||||
|
||||
for (size_t i = 0; i < nOutput; ++i)
|
||||
{
|
||||
Kernel::IAlgorithmProxy* encoder = &this->getAlgorithmManager().getAlgorithm(
|
||||
this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationEncoder));
|
||||
encoder->initialize();
|
||||
CStimulationSet* stimSet = new CStimulationSet();
|
||||
Kernel::TParameterHandler<IStimulationSet*> ip_StimSet(encoder->getInputParameter(OVP_GD_Algorithm_StimulationEncoder_InputParameterId_StimulationSet));
|
||||
ip_StimSet = stimSet;
|
||||
m_encoders.push_back(encoder);
|
||||
m_stimSets.push_back(stimSet);
|
||||
|
||||
m_stimIDsOn.push_back(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i * 2 + 1));
|
||||
m_stimIDsOff.push_back(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i * 2 + 2));
|
||||
}
|
||||
|
||||
const CString name = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
|
||||
m_vrpnButtonRemote = new vrpn_Button_Remote(name.toASCIIString());
|
||||
m_vrpnButtonRemote->register_change_handler(static_cast<void*>(this), vrpn_button_cb);
|
||||
|
||||
m_lastChunkEndTime = uint64_t(-1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmVRPNButtonClient::uninitialize()
|
||||
{
|
||||
const size_t nOutput = this->getStaticBoxContext().getOutputCount();
|
||||
|
||||
delete m_vrpnButtonRemote;
|
||||
m_vrpnButtonRemote = nullptr;
|
||||
|
||||
for (size_t i = 0; i < nOutput; ++i)
|
||||
{
|
||||
delete m_stimSets[i];
|
||||
m_encoders[i]->uninitialize();
|
||||
this->getAlgorithmManager().releaseAlgorithm(*m_encoders[i]);
|
||||
}
|
||||
m_stimSets.clear();
|
||||
m_encoders.clear();
|
||||
m_stimIDsOn.clear();
|
||||
m_stimIDsOff.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmVRPNButtonClient::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBoxAlgorithmVRPNButtonClient::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
const size_t nOutput = this->getStaticBoxContext().getOutputCount();
|
||||
size_t i;
|
||||
|
||||
// Clears pending stimulations
|
||||
for (i = 0; i < nOutput; ++i) { m_stimSets[i]->clear(); }
|
||||
|
||||
// Refreshes VRPN device
|
||||
m_gotStimulation = false;
|
||||
m_vrpnButtonRemote->mainloop();
|
||||
|
||||
while (!m_Buttons.empty())
|
||||
{
|
||||
const std::pair<size_t, bool> state = m_Buttons.front();
|
||||
m_Buttons.pop_front();
|
||||
|
||||
setButton(state.first, state.second);
|
||||
}
|
||||
|
||||
// Encodes streams
|
||||
for (i = 0; i < nOutput; ++i)
|
||||
{
|
||||
Kernel::TParameterHandler<IMemoryBuffer*> op_buffer(
|
||||
m_encoders[i]->getOutputParameter(OVP_GD_Algorithm_StimulationEncoder_OutputParameterId_EncodedMemoryBuffer));
|
||||
op_buffer = boxContext.getOutputChunk(i);
|
||||
if (m_lastChunkEndTime == uint64_t(-1))
|
||||
{
|
||||
m_encoders[i]->process(OVP_GD_Algorithm_StimulationEncoder_InputTriggerId_EncodeHeader);
|
||||
boxContext.markOutputAsReadyToSend(i, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_gotStimulation) { m_encoders[i]->process(OVP_GD_Algorithm_StimulationEncoder_InputTriggerId_EncodeBuffer); }
|
||||
boxContext.markOutputAsReadyToSend(i, m_lastChunkEndTime, this->getPlayerContext().getCurrentTime());
|
||||
}
|
||||
}
|
||||
|
||||
// Updates timings
|
||||
m_lastChunkEndTime = this->getPlayerContext().getCurrentTime();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBoxAlgorithmVRPNButtonClient::setButton(const size_t index, const bool pressed)
|
||||
{
|
||||
const Kernel::IBox& boxContext = this->getStaticBoxContext();
|
||||
|
||||
if (index >= boxContext.getOutputCount())
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "Ignored button " << index + 1 << " with state " << CString(pressed ? "pressed" : "released") << "...\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "Changed button " << index + 1 << " with state " << CString(pressed ? "pressed" : "released") << "...\n";
|
||||
if (pressed) { m_stimSets[index]->appendStimulation(m_stimIDsOn[index], this->getPlayerContext().getCurrentTime(), 0); }
|
||||
else { m_stimSets[index]->appendStimulation(m_stimIDsOff[index], this->getPlayerContext().getCurrentTime(), 0); }
|
||||
m_gotStimulation = true;
|
||||
}
|
||||
}
|
||||
#endif // TARGET_HAS_ThirdPartyVRPN
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <list>
|
||||
#include <vrpn_Button.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
class CBoxAlgorithmVRPNButtonClient final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { delete this; }
|
||||
|
||||
uint64_t getClockFrequency() override { return 128LL << 32; } // the box clock frequency
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_VRPNButtonClient)
|
||||
|
||||
std::list<std::pair<size_t, bool>> m_Buttons;
|
||||
void setButton(const size_t index, const bool pressed);
|
||||
|
||||
protected:
|
||||
|
||||
uint64_t m_lastChunkEndTime = 0;
|
||||
bool m_gotStimulation = false;
|
||||
std::vector<Kernel::IAlgorithmProxy*> m_encoders;
|
||||
std::vector<IStimulationSet*> m_stimSets;
|
||||
std::vector<uint64_t> m_stimIDsOn;
|
||||
std::vector<uint64_t> m_stimIDsOff;
|
||||
vrpn_Button_Remote* m_vrpnButtonRemote = nullptr;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmVRPNButtonClientListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
|
||||
static bool check(Kernel::IBox& box)
|
||||
{
|
||||
for (size_t i = 0; i < box.getOutputCount(); ++i)
|
||||
{
|
||||
const std::string idx = std::to_string(i + 1);
|
||||
box.setOutputName(i, ("Output " + idx).c_str());
|
||||
box.setSettingName(i * 2 + 1, ("Button " + idx + " ON").c_str());
|
||||
box.setSettingName(i * 2 + 2, ("Button " + idx + " OFF").c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onOutputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.setOutputType(index, OV_TypeId_Stimulations);
|
||||
box.addSetting("", OV_TypeId_Stimulation, "OVTK_GDF_Feedback_Continuous");
|
||||
box.addSetting("", OV_TypeId_Stimulation, "OVTK_GDF_End_Of_Trial");
|
||||
return check(box);
|
||||
}
|
||||
|
||||
bool onOutputRemoved(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.removeSetting(index * 2 + 2);
|
||||
box.removeSetting(index * 2 + 1);
|
||||
return check(box);
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CBoxAlgorithmVRPNButtonClientDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("Button VRPN Client"); }
|
||||
CString getAuthorName() const override { return CString("Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("INRIA"); }
|
||||
|
||||
CString getShortDescription() const override
|
||||
{
|
||||
return CString("Connects to an external VRPN device and translate a button information into OpenViBE stimulations");
|
||||
}
|
||||
|
||||
CString getDetailedDescription() const override { return CString("-"); }
|
||||
CString getCategory() const override { return CString("Acquisition and network IO/VRPN"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getStockItemName() const override { return CString("gtk-connect"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_VRPNButtonClient; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmVRPNButtonClient; }
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmVRPNButtonClientListener; }
|
||||
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
// prototype.addInput ("input name", /* input type (OV_TypeId_Signal) */);
|
||||
prototype.addOutput("Output", OV_TypeId_Stimulations);
|
||||
prototype.addSetting("Peripheral name", OV_TypeId_String, "openvibe-vrpn@localhost");
|
||||
prototype.addSetting("Button 1 ON", OV_TypeId_Stimulation, "OVTK_GDF_Feedback_Continuous");
|
||||
prototype.addSetting("Button 1 OFF", OV_TypeId_Stimulation, "OVTK_GDF_End_Of_Trial");
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddOutput);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_VRPNButtonClientDesc)
|
||||
};
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
#endif // TARGET_HAS_ThirdPartyVRPN
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "ovpCVRPNAnalogServer.h"
|
||||
#include "../ovpIVRPNServerManager.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
|
||||
bool CVRPNAnalogServer::initialize()
|
||||
{
|
||||
const size_t nInput = this->getStaticBoxContext().getInputCount();
|
||||
|
||||
// Gets server name, and creates an analog server for this server
|
||||
const CString name = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
|
||||
// Creates the stream decoders
|
||||
for (size_t i = 0; i < nInput; ++i)
|
||||
{
|
||||
m_decoders[i] = &this->getAlgorithmManager().getAlgorithm(this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StreamedMatrixDecoder));
|
||||
m_decoders[i]->initialize();
|
||||
}
|
||||
|
||||
// Creates the peripheral
|
||||
IVRPNServerManager::getInstance().initialize();
|
||||
IVRPNServerManager::getInstance().addServer(name, m_serverID);
|
||||
|
||||
// We don't know the analog count yet before we get a header, so set to zero.
|
||||
// This convention will avoid client problems that misleadingly report 'no response from server'.
|
||||
// The client should check that the channel amount is positive and use that as
|
||||
// an indication of the box having received at least a proper header.
|
||||
IVRPNServerManager::getInstance().setAnalogCount(m_serverID, 0);
|
||||
IVRPNServerManager::getInstance().reportAnalog(m_serverID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNAnalogServer::uninitialize()
|
||||
{
|
||||
const size_t nInput = this->getStaticBoxContext().getInputCount();
|
||||
|
||||
// Releases decoders
|
||||
for (size_t i = 0; i < nInput; ++i)
|
||||
{
|
||||
m_decoders[i]->uninitialize();
|
||||
this->getAlgorithmManager().releaseAlgorithm(*m_decoders[i]);
|
||||
}
|
||||
m_decoders.clear();
|
||||
m_nAnalogs.clear();
|
||||
|
||||
// Releases the peripheral
|
||||
IVRPNServerManager::getInstance().uninitialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNAnalogServer::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
// Note: This call doesn't seem to be necessary for VRPN sending the
|
||||
// data with reportAnarog(). Its utility is likely in keeping the
|
||||
// connection functional during periods with no data.
|
||||
IVRPNServerManager::getInstance().process();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNAnalogServer::processInput(const size_t /*index*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNAnalogServer::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
const size_t nInput = this->getStaticBoxContext().getInputCount();
|
||||
|
||||
for (size_t i = 0; i < nInput; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < boxContext.getInputChunkCount(i); ++j)
|
||||
{
|
||||
Kernel::TParameterHandler<const IMemoryBuffer*> ip_buffer(
|
||||
m_decoders[i]->getInputParameter(OVP_GD_Algorithm_StreamedMatrixDecoder_InputParameterId_MemoryBufferToDecode));
|
||||
Kernel::TParameterHandler<CMatrix*> op_matrix(m_decoders[i]->getOutputParameter(OVP_GD_Algorithm_StreamedMatrixDecoder_OutputParameterId_Matrix));
|
||||
|
||||
ip_buffer = boxContext.getInputChunk(i, j);
|
||||
m_decoders[i]->process();
|
||||
|
||||
CMatrix* matrix = op_matrix;
|
||||
|
||||
if (m_decoders[i]->isOutputTriggerActive(OVP_GD_Algorithm_StreamedMatrixDecoder_OutputTriggerId_ReceivedHeader))
|
||||
{
|
||||
m_nAnalogs[i] = matrix->getBufferElementCount();
|
||||
if (m_nAnalogs.size() == nInput)
|
||||
{
|
||||
size_t nAnalog = 0;
|
||||
for (size_t k = 0; k < nInput; ++k) { nAnalog += m_nAnalogs[k]; }
|
||||
|
||||
if (IVRPNServerManager::getInstance().setAnalogCount(m_serverID, nAnalog))
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "Created VRPN analog server for " << nAnalog << " channel(s)\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to create VRPN analog server for " << nAnalog << " channel(s)\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_analogSet = true;
|
||||
}
|
||||
boxContext.markInputAsDeprecated(i, j);
|
||||
}
|
||||
if (m_analogSet)
|
||||
{
|
||||
if (m_decoders[i]->isOutputTriggerActive(OVP_GD_Algorithm_StreamedMatrixDecoder_OutputTriggerId_ReceivedBuffer))
|
||||
{
|
||||
if (m_analogSet)
|
||||
{
|
||||
size_t offset = 0;
|
||||
for (size_t k = 0; k < i; ++k) { offset += m_nAnalogs[k]; }
|
||||
for (size_t k = 0; k < matrix->getBufferElementCount(); ++k)
|
||||
{
|
||||
if (!IVRPNServerManager::getInstance().setAnalogState(m_serverID, offset + k, matrix->getBuffer()[k]))
|
||||
{
|
||||
getBoxAlgorithmContext()->getPlayerContext()->getLogManager() << Kernel::LogLevel_Warning <<
|
||||
"Could not set analog state for index "
|
||||
<< k << "\n";
|
||||
}
|
||||
}
|
||||
IVRPNServerManager::getInstance().reportAnalog(m_serverID);
|
||||
}
|
||||
}
|
||||
if (m_decoders[i]->isOutputTriggerActive(OVP_GD_Algorithm_StreamedMatrixDecoder_OutputTriggerId_ReceivedEnd)) { }
|
||||
boxContext.markInputAsDeprecated(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
#endif // OVP_HAS_Vrpn
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
class CVRPNAnalogServer final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
|
||||
CVRPNAnalogServer() {}
|
||||
void release() override { delete this; }
|
||||
uint64_t getClockFrequency() override { return 64LL << 32; } // 64hz
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
bool processInput(const size_t index) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithm, OVP_ClassId_VRPNAnalogServer)
|
||||
|
||||
protected:
|
||||
|
||||
CIdentifier m_serverID = CIdentifier::undefined();
|
||||
bool m_analogSet = false;
|
||||
|
||||
std::map<size_t, Kernel::IAlgorithmProxy*> m_decoders;
|
||||
std::map<size_t, size_t> m_nAnalogs;
|
||||
};
|
||||
|
||||
class CVRPNAnalogServerListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
|
||||
static bool check(Kernel::IBox& box)
|
||||
{
|
||||
for (size_t i = 0; i < box.getInputCount(); ++i)
|
||||
{
|
||||
box.setInputName(i, ("Input " + std::to_string(i + 1)).c_str());
|
||||
box.setInputType(i, OV_TypeId_StreamedMatrix);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onInputRemoved(Kernel::IBox& box, const size_t /*index*/) override { return check(box); }
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t /*index*/) override { return check(box); }
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CVRPNAnalogServerDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
CString getName() const override { return CString("Analog VRPN Server"); }
|
||||
CString getAuthorName() const override { return CString("Bruno Renier/Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("INRIA"); }
|
||||
CString getShortDescription() const override { return CString("Creates VRPN analog servers (one per input)."); }
|
||||
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return CString("Creates VRPN analog servers to make data from the plugin's inputs available to VRPN client applications.");
|
||||
}
|
||||
|
||||
CString getCategory() const override { return CString("Acquisition and network IO/VRPN"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getStockItemName() const override { return CString("gtk-connect"); }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_VRPNAnalogServer; }
|
||||
IPluginObject* create() override { return new CVRPNAnalogServer(); }
|
||||
IBoxListener* createBoxListener() const override { return new CVRPNAnalogServerListener; }
|
||||
void release() override { }
|
||||
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Input 1", OV_TypeId_StreamedMatrix);
|
||||
prototype.addSetting("Peripheral name", OV_TypeId_String, "openvibe-vrpn");
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_VRPNAnalogServerDesc)
|
||||
};
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // OVP_HAS_Vrpn
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "ovpCVRPNButtonServer.h"
|
||||
#include "../ovpIVRPNServerManager.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
|
||||
bool CVRPNButtonServer::initialize()
|
||||
{
|
||||
const Kernel::IBox* box = getBoxAlgorithmContext()->getStaticBoxContext();
|
||||
|
||||
//get server name, and creates a button server for this server
|
||||
const CString name = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
|
||||
IVRPNServerManager::getInstance().initialize();
|
||||
IVRPNServerManager::getInstance().addServer(name, m_serverID);
|
||||
IVRPNServerManager::getInstance().setButtonCount(m_serverID, box->getInputCount());
|
||||
|
||||
m_decoders.resize(box->getInputCount());
|
||||
|
||||
//get stim id
|
||||
for (size_t i = 0; i < box->getInputCount(); ++i)
|
||||
{
|
||||
CString onStimulationID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1 + i * 2);
|
||||
CString offStimulationID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2 + i * 2);
|
||||
m_stimulationPairs[i] = std::pair<uint64_t, uint64_t>(
|
||||
getBoxAlgorithmContext()->getPlayerContext()->getTypeManager().getEnumerationEntryValueFromName(OVTK_TypeId_Stimulation, onStimulationID),
|
||||
getBoxAlgorithmContext()->getPlayerContext()->getTypeManager().getEnumerationEntryValueFromName(OVTK_TypeId_Stimulation, offStimulationID));
|
||||
|
||||
m_decoders[i] = new Toolkit::TStimulationDecoder<CVRPNButtonServer>;
|
||||
m_decoders[i]->initialize(*this, i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNButtonServer::uninitialize()
|
||||
{
|
||||
for (size_t i = 0; i < m_decoders.size(); ++i) { delete m_decoders[i]; }
|
||||
m_decoders.clear();
|
||||
|
||||
IVRPNServerManager::getInstance().uninitialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNButtonServer::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
IVRPNServerManager::getInstance().process();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNButtonServer::processInput(const size_t /*index*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNButtonServer::process()
|
||||
{
|
||||
Kernel::IBoxIO* boxIO = getBoxAlgorithmContext()->getDynamicBoxContext();
|
||||
|
||||
for (size_t input = 0; input < getBoxAlgorithmContext()->getStaticBoxContext()->getInputCount(); ++input)
|
||||
{
|
||||
m_currInput = input;
|
||||
|
||||
for (size_t chunk = 0; chunk < boxIO->getInputChunkCount(input); ++chunk)
|
||||
{
|
||||
m_decoders[input]->decode(chunk);
|
||||
|
||||
if (m_decoders[input]->isBufferReceived())
|
||||
{
|
||||
const IStimulationSet* stimSet = m_decoders[input]->getOutputStimulationSet();
|
||||
for (size_t s = 0; s < stimSet->getStimulationCount(); ++s)
|
||||
{
|
||||
setStimulation(s, stimSet->getStimulationIdentifier(s), stimSet->getStimulationDate(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CVRPNButtonServer::setStimulation(const size_t /*index*/, const uint64_t id, const uint64_t /*date*/)
|
||||
{
|
||||
const std::pair<uint64_t, uint64_t> stimulationPair = m_stimulationPairs[m_currInput];
|
||||
|
||||
if (stimulationPair.first == stimulationPair.second)
|
||||
{
|
||||
if (stimulationPair.first == id)
|
||||
{
|
||||
getBoxAlgorithmContext()->getPlayerContext()->getLogManager() << Kernel::LogLevel_Trace << "Received TOGGLE stimulation for button "
|
||||
<< m_currInput << " (" << id << ")\n";
|
||||
IVRPNServerManager::getInstance().setButtonState(m_serverID, m_currInput,
|
||||
!IVRPNServerManager::getInstance().getButtonState(m_serverID, m_currInput));
|
||||
IVRPNServerManager::getInstance().reportButton(m_serverID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stimulationPair.first == id)
|
||||
{
|
||||
getBoxAlgorithmContext()->getPlayerContext()->getLogManager() << Kernel::LogLevel_Trace << "Received ON stimulation for button "
|
||||
<< m_currInput << " (" << id << ")\n";
|
||||
IVRPNServerManager::getInstance().setButtonState(m_serverID, m_currInput, true);
|
||||
IVRPNServerManager::getInstance().reportButton(m_serverID);
|
||||
}
|
||||
if (stimulationPair.second == id)
|
||||
{
|
||||
getBoxAlgorithmContext()->getPlayerContext()->getLogManager() << Kernel::LogLevel_Trace << "Received OFF stimulation for button "
|
||||
<< m_currInput << " (" << id << ")\n";
|
||||
IVRPNServerManager::getInstance().setButtonState(m_serverID, m_currInput, false);
|
||||
IVRPNServerManager::getInstance().reportButton(m_serverID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
#endif // OVP_HAS_Vrpn
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
#pragma once
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
#include <map>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
class CVRPNButtonServer final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
|
||||
CVRPNButtonServer() {}
|
||||
void release() override { delete this; }
|
||||
uint64_t getClockFrequency() override { return 64LL << 32; } // 64 times per second
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
bool processInput(const size_t index) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithm, OVP_ClassId_VRPNButtonServer)
|
||||
|
||||
void setStimulation(const size_t index, const uint64_t id, const uint64_t date);
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<Toolkit::TStimulationDecoder<CVRPNButtonServer>*> m_decoders;
|
||||
|
||||
//Start and end time of the last buffer
|
||||
uint64_t m_startTime = 0;
|
||||
uint64_t m_endTime = 0;
|
||||
|
||||
size_t m_currInput = 0;
|
||||
|
||||
CIdentifier m_serverID = CIdentifier::undefined();
|
||||
|
||||
//Pairs of start/stop stimulations id
|
||||
std::map<size_t, std::pair<uint64_t, uint64_t>> m_stimulationPairs;
|
||||
};
|
||||
|
||||
class CVRPNButtonServerListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
|
||||
bool check(Kernel::IBox& box) const
|
||||
{
|
||||
for (size_t i = 0; i < box.getInputCount(); ++i)
|
||||
{
|
||||
box.setInputName(i, ("Input " + std::to_string(i + 1)).c_str());
|
||||
box.setInputType(i, OV_TypeId_Stimulations);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < box.getInputCount(); ++i)
|
||||
{
|
||||
box.setSettingName(i * 2 + 1, ("Button " + std::to_string(i + 1) + " ON").c_str());
|
||||
box.setSettingType(i * 2 + 1, OV_TypeId_Stimulation);
|
||||
|
||||
box.setSettingName(i * 2 + 2, ("Button " + std::to_string(i + 1) + " OFF").c_str());
|
||||
box.setSettingType(i * 2 + 2, OV_TypeId_Stimulation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onInputRemoved(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.removeSetting(index * 2 + 1);
|
||||
box.removeSetting(index * 2 + 1);
|
||||
|
||||
return this->check(box);
|
||||
}
|
||||
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t /*index*/) override
|
||||
{
|
||||
box.addSetting("", OV_TypeId_Stimulation, "OVTK_GDF_Feedback_Continuous");
|
||||
box.addSetting("", OV_TypeId_Stimulation, "OVTK_GDF_End_Of_Trial");
|
||||
|
||||
return this->check(box);
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CVRPNButtonServerDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
CString getName() const override { return CString("Button VRPN Server"); }
|
||||
CString getAuthorName() const override { return CString("Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("INRIA"); }
|
||||
CString getShortDescription() const override { return CString("Creates VRPN button servers (one per input)."); }
|
||||
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return CString("Creates VRPN button servers to make data from the plugin's inputs available to VRPN client applications.");
|
||||
}
|
||||
|
||||
CString getCategory() const override { return CString("Acquisition and network IO/VRPN"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getStockItemName() const override { return CString("gtk-connect"); }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_VRPNButtonServer; }
|
||||
IPluginObject* create() override { return new CVRPNButtonServer(); }
|
||||
IBoxListener* createBoxListener() const override { return new CVRPNButtonServerListener; }
|
||||
void release() override { }
|
||||
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Input 1", OVTK_TypeId_Stimulations);
|
||||
prototype.addSetting("Peripheral name", OV_TypeId_String, "openvibe-vrpn");
|
||||
prototype.addSetting("Button 1 ON", OV_TypeId_Stimulation, "OVTK_GDF_Feedback_Continuous");
|
||||
prototype.addSetting("Button 1 OFF", OV_TypeId_Stimulation, "OVTK_GDF_End_Of_Trial");
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_VRPNButtonServerDesc)
|
||||
};
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // OVP_HAS_Vrpn
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include "ovpIVRPNServerManager.h"
|
||||
|
||||
#include <vrpn_Connection.h>
|
||||
#include <vrpn_Analog.h>
|
||||
#include <vrpn_Button.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
namespace {
|
||||
class CVRPNServerManager final : public IVRPNServerManager
|
||||
{
|
||||
public:
|
||||
|
||||
CVRPNServerManager() { }
|
||||
~CVRPNServerManager() override { }
|
||||
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
|
||||
bool process() override;
|
||||
bool reportAnalog(const CIdentifier& serverID) override;
|
||||
bool reportButton(const CIdentifier& serverID) override;
|
||||
|
||||
bool addServer(const CString& name, CIdentifier& identifier) override;
|
||||
bool isServer(const CIdentifier& identifier) const override;
|
||||
bool isServer(const CString& name) const override;
|
||||
bool getServerIdentifier(const CString& name, CIdentifier& identifier) const override;
|
||||
bool getServerName(const CIdentifier& serverID, CString& name) const override;
|
||||
bool removeServer(const CIdentifier& serverID) override;
|
||||
|
||||
bool setButtonCount(const CIdentifier& serverID, size_t nButton) override;
|
||||
bool setButtonState(const CIdentifier& serverID, size_t buttonIndex, bool status) override;
|
||||
bool getButtonState(const CIdentifier& serverID, size_t buttonIndex) const override;
|
||||
|
||||
bool setAnalogCount(const CIdentifier& serverID, size_t nAnalog) override;
|
||||
bool setAnalogState(const CIdentifier& serverID, size_t analogIndex, double status) override;
|
||||
double getAnalogState(const CIdentifier& serverID, size_t analogIndex) const override;
|
||||
|
||||
protected:
|
||||
|
||||
vrpn_Connection* m_connection = nullptr;
|
||||
|
||||
std::map<CIdentifier, CString> m_serverNames;
|
||||
std::map<CIdentifier, vrpn_Button_Server*> m_buttonServers;
|
||||
std::map<CIdentifier, vrpn_Analog_Server*> m_analogServers;
|
||||
std::map<CIdentifier, std::vector<bool>> m_buttonCaches;
|
||||
|
||||
size_t m_nInitialize = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
IVRPNServerManager& IVRPNServerManager::getInstance()
|
||||
{
|
||||
static CVRPNServerManager gVRPNServerManager;
|
||||
return gVRPNServerManager;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::initialize()
|
||||
{
|
||||
if (!m_nInitialize)
|
||||
{
|
||||
//m_Connection=new vrpn_Connection;
|
||||
m_connection = vrpn_create_server_connection();
|
||||
}
|
||||
m_nInitialize++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::uninitialize()
|
||||
{
|
||||
m_nInitialize--;
|
||||
if (!m_nInitialize)
|
||||
{
|
||||
for (auto it = m_analogServers.begin(); it != m_analogServers.end(); ++it)
|
||||
{
|
||||
if (it->second)
|
||||
{
|
||||
delete it->second;
|
||||
it->second = nullptr;
|
||||
}
|
||||
}
|
||||
m_analogServers.clear();
|
||||
for (auto it = m_buttonServers.begin(); it != m_buttonServers.end(); ++it)
|
||||
{
|
||||
if (it->second)
|
||||
{
|
||||
delete it->second;
|
||||
it->second = nullptr;
|
||||
}
|
||||
}
|
||||
m_buttonServers.clear();
|
||||
|
||||
// $$$ UGLY !
|
||||
// The following function should destroy correctly the connection, but does not.
|
||||
//vrpn_ConnectionManager::instance().deleteConnection(m_Connection);
|
||||
delete m_connection;
|
||||
m_connection = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::process()
|
||||
{
|
||||
for (auto it = m_analogServers.begin(); it != m_analogServers.end(); ++it) { if (it->second) { it->second->mainloop(); } }
|
||||
for (auto it = m_buttonServers.begin(); it != m_buttonServers.end(); ++it) { if (it->second) { it->second->mainloop(); } }
|
||||
if (m_connection) { m_connection->mainloop(); }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::reportAnalog(const CIdentifier& serverID)
|
||||
{
|
||||
auto it = m_analogServers.find(serverID);
|
||||
if (it != m_analogServers.end())
|
||||
{
|
||||
if (it->second)
|
||||
{
|
||||
// This is public function and mainloop won't call it for me
|
||||
// Thank you VRPN for this to be similar to button behavior ;o)
|
||||
it->second->report();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::reportButton(const CIdentifier& serverID)
|
||||
{
|
||||
const auto it = m_buttonServers.find(serverID);
|
||||
if (it != m_buttonServers.end())
|
||||
{
|
||||
if (it->second)
|
||||
{
|
||||
// This is not public function, however, mainloop calls it for me
|
||||
// Thank you VRPN for this to be similar to analog behavior ;o)
|
||||
// itButtonServer->second->report_changes();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::addServer(const CString& name, CIdentifier& identifier)
|
||||
{
|
||||
if (this->isServer(name)) { return this->getServerIdentifier(name, identifier); }
|
||||
|
||||
identifier = CIdentifier::random();
|
||||
while (m_serverNames.find(identifier) != m_serverNames.end()) { ++identifier; }
|
||||
|
||||
m_serverNames[identifier] = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::isServer(const CIdentifier& identifier) const { return m_serverNames.find(identifier) != m_serverNames.end(); }
|
||||
|
||||
bool CVRPNServerManager::isServer(const CString& name) const
|
||||
{
|
||||
for (auto it = m_serverNames.begin(); it != m_serverNames.end(); ++it) { if (it->second == name) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::getServerIdentifier(const CString& name, CIdentifier& identifier) const
|
||||
{
|
||||
for (auto it = m_serverNames.begin(); it != m_serverNames.end(); ++it)
|
||||
{
|
||||
if (it->second == name)
|
||||
{
|
||||
identifier = it->first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::getServerName(const CIdentifier& serverID, CString& name) const
|
||||
{
|
||||
const auto it = m_serverNames.find(serverID);
|
||||
if (it == m_serverNames.end()) { return false; }
|
||||
name = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::removeServer(const CIdentifier& serverID)
|
||||
{
|
||||
if (!this->isServer(serverID)) { return false; }
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::setButtonCount(const CIdentifier& serverID, const size_t nButton)
|
||||
{
|
||||
if (!this->isServer(serverID)) { return false; }
|
||||
delete m_buttonServers[serverID];
|
||||
m_buttonServers[serverID] = new vrpn_Button_Server(m_serverNames[serverID], m_connection, int(nButton));
|
||||
m_buttonCaches[serverID].clear();
|
||||
m_buttonCaches[serverID].resize(nButton);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::setButtonState(const CIdentifier& serverID, const size_t buttonIndex, const bool status)
|
||||
{
|
||||
if (!this->isServer(serverID) || m_buttonServers.find(serverID) == m_buttonServers.end()) { return false; }
|
||||
m_buttonServers[serverID]->set_button(int(buttonIndex), status ? 1 : 0);
|
||||
m_buttonCaches[serverID][buttonIndex] = status;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::getButtonState(const CIdentifier& serverID, const size_t buttonIndex) const
|
||||
{
|
||||
if (!this->isServer(serverID)) { return false; }
|
||||
const auto itButtonServer = m_buttonServers.find(serverID);
|
||||
if (itButtonServer == m_buttonServers.end()) { return false; }
|
||||
const auto itButtonCache = m_buttonCaches.find(serverID);
|
||||
return itButtonCache->second[buttonIndex];
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::setAnalogCount(const CIdentifier& serverID, const size_t nAnalog)
|
||||
{
|
||||
if (!this->isServer(serverID)) { return false; }
|
||||
if (m_analogServers[serverID]) { delete m_analogServers[serverID]; }
|
||||
m_analogServers[serverID] = new vrpn_Analog_Server(m_serverNames[serverID], m_connection);
|
||||
if (size_t(m_analogServers[serverID]->setNumChannels(vrpn_uint32(nAnalog))) != nAnalog) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVRPNServerManager::setAnalogState(const CIdentifier& serverID, const size_t analogIndex, const double status)
|
||||
{
|
||||
if (!this->isServer(serverID) || m_analogServers.find(serverID) == m_analogServers.end()) { return false; }
|
||||
const size_t nChannel = m_analogServers[serverID]->getNumChannels();
|
||||
if (analogIndex >= nChannel) { return false; }
|
||||
|
||||
m_analogServers[serverID]->channels()[analogIndex] = status;
|
||||
return true;
|
||||
}
|
||||
|
||||
double CVRPNServerManager::getAnalogState(const CIdentifier& serverID, const size_t analogIndex) const
|
||||
{
|
||||
if (!this->isServer(serverID)) { return 0; }
|
||||
auto it = m_analogServers.find(serverID);
|
||||
if (it == m_analogServers.end()) { return 0; }
|
||||
return it->second->channels()[analogIndex];
|
||||
}
|
||||
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
#endif // OVP_HAS_Vrpn
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
class IVRPNServerManager
|
||||
{
|
||||
public:
|
||||
|
||||
static IVRPNServerManager& getInstance();
|
||||
|
||||
virtual ~IVRPNServerManager() { }
|
||||
|
||||
virtual bool initialize() = 0;
|
||||
virtual bool uninitialize() = 0;
|
||||
|
||||
virtual bool process() = 0;
|
||||
virtual bool reportAnalog(const CIdentifier& identifier) = 0;
|
||||
virtual bool reportButton(const CIdentifier& identifier) = 0;
|
||||
|
||||
virtual bool addServer(const CString& name, CIdentifier& identifier) = 0;
|
||||
virtual bool isServer(const CIdentifier& identifier) const = 0;
|
||||
virtual bool isServer(const CString& name) const = 0;
|
||||
virtual bool getServerIdentifier(const CString& name, CIdentifier& identifier) const = 0;
|
||||
virtual bool getServerName(const CIdentifier& identifier, CString& name) const = 0;
|
||||
virtual bool removeServer(const CIdentifier& identifier) = 0;
|
||||
|
||||
virtual bool setButtonCount(const CIdentifier& identifier, size_t nButton) = 0;
|
||||
virtual bool setButtonState(const CIdentifier& identifier, size_t buttonIndex, bool status) = 0;
|
||||
virtual bool getButtonState(const CIdentifier& identifier, size_t buttonIndex) const = 0;
|
||||
|
||||
virtual bool setAnalogCount(const CIdentifier& serverID, size_t nAnalog) = 0;
|
||||
virtual bool setAnalogState(const CIdentifier& serverID, size_t analogIndex, double status) = 0;
|
||||
virtual double getAnalogState(const CIdentifier& serverID, size_t analogIndex) const = 0;
|
||||
};
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // OVP_HAS_Vrpn
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
// Boxes
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OVP_ClassId_VRPNAnalogServer OpenViBE::CIdentifier(0x0DDC3A7E, 0x6F6E6401)
|
||||
#define OVP_ClassId_VRPNAnalogServerDesc OpenViBE::CIdentifier(0xF54B8E03, 0xAAFF15C6)
|
||||
#define OVP_ClassId_VRPNButtonServer OpenViBE::CIdentifier(0x0E382E6F, 0x5BE1F00C)
|
||||
#define OVP_ClassId_VRPNButtonServerDesc OpenViBE::CIdentifier(0xBC86F256, 0x002495EF)
|
||||
#define OVP_ClassId_BoxAlgorithm_VRPNAnalogClient OpenViBE::CIdentifier(0x7CF4A95E, 0x7270D07B)
|
||||
#define OVP_ClassId_BoxAlgorithm_VRPNAnalogClientDesc OpenViBE::CIdentifier(0x77B2AE79, 0xFDC31871)
|
||||
#define OVP_ClassId_BoxAlgorithm_VRPNButtonClient OpenViBE::CIdentifier(0x40714327, 0x458877D2)
|
||||
#define OVP_ClassId_BoxAlgorithm_VRPNButtonClientDesc OpenViBE::CIdentifier(0x16FB6283, 0x45EC313F)
|
||||
|
||||
|
||||
// Global defines
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#ifdef TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
|
||||
#include "ovp_global_defines.h"
|
||||
#endif // TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
#include "ovp_defines.h"
|
||||
#include "box-algorithms/ovpCVRPNAnalogServer.h"
|
||||
#include "box-algorithms/ovpCVRPNButtonServer.h"
|
||||
#include "box-algorithms/ovpCBoxAlgorithmVRPNAnalogClient.h"
|
||||
#include "box-algorithms/ovpCBoxAlgorithmVRPNButtonClient.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace VRPN {
|
||||
|
||||
OVP_Declare_Begin()
|
||||
#if defined TARGET_HAS_ThirdPartyVRPN
|
||||
OVP_Declare_New(CVRPNAnalogServerDesc);
|
||||
OVP_Declare_New(CVRPNButtonServerDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmVRPNAnalogClientDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmVRPNButtonClientDesc);
|
||||
#endif
|
||||
|
||||
OVP_Declare_End()
|
||||
|
||||
} // namespace VRPN
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
Reference in New Issue
Block a user