This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,147 @@
#include "ovpCBoxAlgorithm@@ClassName@@.h"
using namespace OpenViBE;
using namespace /*OpenViBE::*/Kernel;
using namespace /*OpenViBE::*/Plugins;
using namespace /*OpenViBE::Plugins::*/@@Namespace@@;
bool CBoxAlgorithm@@ClassName@@::initialize()
{
@@AlgorithmInitialisation@@
// If you need to retrieve setting values, use the FSettingValueAutoCast function.
// For example :
// - CString setting at index 0 in the setting list :
// CString sSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
// - unsigned int64 setting at index 1 in the setting list :
// uint64_t uiSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
// - double setting at index 2 in the setting list :
// double doubleSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
// ...
return true;
}
/*******************************************************************************/
bool CBoxAlgorithm@@ClassName@@::uninitialize()
{
@@AlgorithmUninitialisation@@
return true;
}
/*******************************************************************************/
@@ProcessClockCommentIn@@
bool CBoxAlgorithm@@ClassName@@::processClock(Kernel::CMessageClock& msg)
{
// some pre-processing code if needed...
// ready to process !
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
@@ProcessClockCommentOut@@
/*******************************************************************************/
@@ProcessClockCommentIn@@
uint64_t CBoxAlgorithm@@ClassName@@::getClockFrequency()
{
// Note that the time is coded on a 64 bits unsigned integer, fixed decimal point (32:32)
return @@ClockFrequency@@; // the box clock frequency
}
@@ProcessClockCommentOut@@
/*******************************************************************************/
@@ProcessInputCommentIn@@
bool CBoxAlgorithm@@ClassName@@::processInput(const size_t index)
{
// some pre-processing code if needed...
// ready to process !
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
@@ProcessInputCommentOut@@
/*******************************************************************************/
bool CBoxAlgorithm@@ClassName@@::process()
{
// the static box context describes the box inputs, outputs, settings structures
const IBox& staticBoxContext=this->getStaticBoxContext();
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
IBoxIO& boxContext = this->getDynamicBoxContext();
// here is some useful functions:
// - To get input/output/setting count:
// staticBoxContext.getInputCount();
// staticBoxContext.getOutputCount();
// - To get the number of chunks currently available on a particular input :
// boxContext.getInputChunkCount(input_index)
// - To send an output chunk :
// boxContext.markOutputAsReadyToSend(output_index, chunk_start_time, chunk_end_time);
// A typical process iteration may look like this.
// This example only iterate over the first input of type Signal, and output a modified Signal.
// thus, the box uses 1 decoder (m_signalDecoder) and 1 encoder (m_signalEncoder)
/*
IBoxIO& boxContext = this->getDynamicBoxContext();
//iterate over all chunk on input 0
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
{
// decode the chunk i
m_signalDecoder.decode(i);
// the decoder may have decoded 3 different parts : the header, a buffer or the end of stream.
if(m_signalDecoder.isHeaderReceived())
{
// Header received. This happens only once when pressing "play". For example with a StreamedMatrix input, you now know the dimension count, sizes, and labels of the matrix
// ... maybe do some process ...
// Pass the header to the next boxes, by encoding a header on the output 0:
m_signalEncoder.encodeHeader(0);
// send the output chunk containing the header. The dates are the same as the input chunk:
boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
}
if(m_signalDecoder.isBufferReceived())
{
// Buffer received. For example the signal values
// Access to the buffer can be done thanks to :
CMatrix* matrix = m_signalDecoder.getOutputMatrix(); // the StreamedMatrix of samples.
uint64_t frequency = m_signalDecoder.getOutputSamplingRate(); // the sampling rate of the signal
// ... do some process on the matrix ...
// Encode the output buffer :
m_signalEncoder.encodeBuffer(0);
// and send it to the next boxes :
boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
}
if(m_signalDecoder.isEndReceived())
{
// End of stream received. This happens only once when pressing "stop". Just pass it to the next boxes so they receive the message :
m_signalEncoder.encodeEnd(0);
boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
}
// The current input chunk has been processed, and automaticcaly discarded.
// you don't need to call "boxContext.markInputAsDeprecated(0, i);"
}
*/
// check the official developer documentation webpage for more example and information :
// Tutorials:
// http://openvibe.inria.fr/documentation/#Developer+Documentation
// Codec Toolkit page :
// http://openvibe.inria.fr/codec-toolkit-references/
// Feel free to ask experienced developers on the forum (http://openvibe.inria.fr/forum) and IRC (#openvibe on irc.freenode.net).
return true;
}
@@ -0,0 +1,148 @@
#include "ovpCBoxAlgorithm@@ClassName@@.h"
using namespace OpenViBE;
using namespace /*OpenViBE::*/Kernel;
using namespace /*OpenViBE::*/Plugins;
using namespace /*OpenViBE::Plugins::*/@@Namespace@@;
bool CBoxAlgorithm@@ClassName@@::initialize()
{
@@AlgorithmInitialisation@@
// If you need to retrieve setting values, use the FSettingValueAutoCast function.
// For example :
// - CString setting at index 0 in the setting list :
// CString sSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
// - unsigned int64 setting at index 1 in the setting list :
// uint64_t uiSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
// - double setting at index 2 in the setting list :
// double doubleSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
// ...
return true;
}
/*******************************************************************************/
bool CBoxAlgorithm@@ClassName@@::uninitialize()
{
@@AlgorithmUninitialisation@@
return true;
}
/*******************************************************************************/
@@ProcessClockCommentIn@@
bool CBoxAlgorithm@@ClassName@@::processClock(Kernel::CMessageClock& msg)
{
// some pre-processing code if needed...
// ready to process !
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
/*******************************************************************************/
@@ProcessClockCommentIn@@
uint64_t CBoxAlgorithm@@ClassName@@::getClockFrequency()
{
// Note that the time is coded on a 64 bits unsigned integer, fixed decimal point (32:32)
return @@ClockFrequency@@; // the box clock frequency
}
/*******************************************************************************/
@@ProcessInputCommentIn@@
bool CBoxAlgorithm@@ClassName@@::processInput(const size_t /*index*/)
{
// some pre-processing code if needed...
// ready to process !
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
/*******************************************************************************/
bool CBoxAlgorithm@@ClassName@@::process()
{
// the static box context describes the box inputs, outputs, settings structures
const IBox& staticBoxCtx = this->getStaticBoxContext();
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
IBoxIO& boxCtx = this->getDynamicBoxContext();
// here is some useful functions:
// - To get input/output/setting count:
// staticBoxCtx.getInputCount();
// staticBoxCtx.getOutputCount();
// staticBoxCtx.getSettingCount();
// - To get the chunks currently available on a particular input :
// boxCtx.getInputChunkCount(input_index)
// boxCtx.getInputChunk(input_index, chunk_index)
// - To get the chunk available on a particular output :
// boxCtx.getOutputChunk(output_index)
// - To send an output chunk :
// boxCtx.markOutputAsReadyToSend(output_index, chunk_start_time, chunk_end_time);
// A typical process iteration may look like this.
// This example only iterate over the first input.
/*
IBoxIO& boxCtx = this->getDynamicBoxContext();
//iterate over all chunk on input 0
for (size_t i = 0; i < boxCtx.getInputChunkCount(0); ++i)
{
// fill the decoder input with input chunk
ip_bufferToDecode = boxCtx.getInputChunk(0, i);
// link the encoder output to box output chunk
op_buffer = boxCtx.getOutputChunk(0);
// decode the input chunk
m_decoder->process();
// the decoder may have decoded 3 different parts : the header, a buffer or the end of stream.
// 3 corresponding output triggers may rise.
// the decoded block is now in the decoded output (let's say op_pDecodedMatrix)
if(m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_SignalDecoder_OutputTriggerId_ReceivedHeader))
{
// Header received. This happens only once when pressing "play". For example with a StreamedMatrix input, you now know the dimension count size, and label of the matrix
// ... do some process ...
// Pass the header to the next boxes, by encoding it :
m_encoder->process(OVP_GD_Algorithm_SignalEncoder_InputTriggerId_EncodeHeader);
// send the output chunk containing the header :
boxCtx.markOutputAsReadyToSend(0, boxCtx.getInputChunkStartTime(0, i), boxCtx.getInputChunkEndTime(0, i));
}
if(m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_SignalDecoder_OutputTriggerId_ReceivedBuffer))
{
// Buffer received. For example the matrix values
// Access to the matrix buffer can be done thanks to :
// op_pDecodedMatrix->getBuffer(), which is a one-dimension vector of value.
// ... do some process ...
// Encode the output buffer :
m_encoder->process(OVP_GD_Algorithm_SignalEncoder_InputTriggerId_EncodeBuffer);
// and send it to the next boxes :
boxCtx.markOutputAsReadyToSend(0, boxCtx.getInputChunkStartTime(0, i), boxCtx.getInputChunkEndTime(0, i));
}
if(m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_SignalDecoder_OutputTriggerId_ReceivedEnd))
{
// End of stream received. This happens only once when pressing "stop". Just pass it to the next boxes so they receive the message :
m_encoder->process(OVP_GD_Algorithm_SignalEncoder_InputTriggerId_EncodeEnd);
boxCtx.markOutputAsReadyToSend(0, boxCtx.getInputChunkStartTime(0, i), boxCtx.getInputChunkEndTime(0, i));
}
// The current input chunk has been processed, let's discard it :
boxCtx.markInputAsDeprecated(0, i);
}
*/
// check the official developer documentation webpage for more example and information :
// http://openvibe.inria.fr/documentation/#Developer+Documentation
// Feel free to ask experienced developers on the forum (http://openvibe.inria.fr/forum) and IRC (#openvibe on irc.freenode.net).
return true;
}
@@ -0,0 +1,149 @@
///-------------------------------------------------------------------------------------------------
///
/// \file CBoxAlgorithm@@ClassName@@.h
/// \brief Classes of the Box @@BoxName@@.
/// \author @@Author@@ (@@Company@@).
/// \version @@Version@@.
/// \date @@Date@@.
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
///
///-------------------------------------------------------------------------------------------------
#pragma once
//You may have to change this path to match your folder organisation
#include "ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
// The unique identifiers for the box and its descriptor.
// Identifier are randomly chosen by the skeleton-generator.
#define OVP_ClassId_BoxAlgorithm_@@ClassName@@ OpenViBE::CIdentifier@@RandomIdentifierClass@@
#define OVP_ClassId_BoxAlgorithm_@@ClassName@@Desc OpenViBE::CIdentifier@@RandomIdentifierDescriptor@@
#define OV_AttributeId_Box_FlagIsUnstable OpenViBE::CIdentifier(0x666FFFFF, 0x666FFFFF)
namespace OpenViBE
{
namespace Plugins
{
namespace @@Namespace@@
{
/// <summary> The class CBoxAlgorithm@@ClassName@@ describes the box @@BoxName@@. </summary>
class CBoxAlgorithm@@ClassName@@ final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
void release() override { delete this; }
bool initialize() override;
bool uninitialize() override;
//Here is the different process callbacks possible
// - On clock ticks :
@@ProcessClockComment@@bool processClock(Kernel::CMessageClock& msg) override;
// - On new input received (the most common behaviour for signal processing) :
@@ProcessInputComment@@bool processInput(const size_t index) override;
// If you want to use processClock, you must provide the clock frequency.
@@ProcessClockComment@@uint64_t getClockFrequency() override;
bool process() override;
// As we do with any class in openvibe, we use the macro below to associate this box to an unique identifier.
// The inheritance information is also made available, as we provide the superclass Toolkit::TBoxAlgorithm < IBoxAlgorithm >
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_@@ClassName@@)
protected:
@@Algorithms@@
};
// If you need to implement a box Listener, here is a sekeleton for you.
// Use only the callbacks you need.
// For example, if your box has a variable number of input, but all of them must be stimulation inputs.
// The following listener callback will ensure that any newly added input is stimulations :
/*
bool onInputAdded(Kernel::IBox& box, const size_t index) override
{
box.setInputType(index, OV_TypeId_Stimulations);
};
*/
@@BoxListenerCommentIn@@
// The box listener can be used to call specific callbacks whenever the box structure changes : input added, name changed, etc.
// Please uncomment below the callbacks you want to use.
/// <summary> Listener of the box @@BoxName@@. </summary>
class CBoxAlgorithm@@ClassName@@Listener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
//bool onInitialized(Kernel::IBox& box) override { return true; };
//bool onNameChanged(Kernel::IBox& box) override { return true; };
@@BoxListenerOnInputConnectedComment@@bool onInputConnected(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnInputDisconnectedComment@@bool onInputDisconnected(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnInputAddedComment@@bool onInputAdded(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnInputRemovedComment@@bool onInputRemoved(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnInputTypeChangedComment@@bool onInputTypeChanged(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnInputNameChangedComment@@bool onInputNameChanged(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnOutputConnectedComment@@bool onOutputConnected(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnOutputDisconnectedComment@@bool onOutputDisconnected(Kernel::IBox& box, const size_t index) { return true; };
@@BoxListenerOnOutputAddedComment@@bool onOutputAdded(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnOutputRemovedComment@@bool onOutputRemoved(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnOutputTypeChangedComment@@bool onOutputTypeChanged(Kernel::IBox& box, const size_t index) override override { return true; };
@@BoxListenerOnOutputNameChangedComment@@bool onOutputNameChanged(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnSettingAddedComment@@bool onSettingAdded(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnSettingRemovedComment@@bool onSettingRemoved(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnSettingTypeChangedComment@@bool onSettingTypeChanged(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnSettingNameChangedComment@@bool onSettingNameChanged(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnSettingDefaultValueChangedComment@@bool onSettingDefaultValueChanged(Kernel::IBox& box, const size_t index) override { return true; };
@@BoxListenerOnSettingValueChangedComment@@bool onSettingValueChanged(Kernel::IBox& box, const size_t index) override { return true; };
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
@@BoxListenerCommentOut@@
/// <summary> Descriptor of the box @@BoxName@@. </summary>
class CBoxAlgorithm@@ClassName@@Desc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("@@BoxName@@"); }
CString getAuthorName() const override { return CString("@@Author@@"); }
CString getAuthorCompanyName() const override { return CString("@@Company@@"); }
CString getShortDescription() const override { return CString("@@ShortDescription@@"); }
CString getDetailedDescription() const override { return CString("@@DetailedDescription@@"); }
CString getCategory() const override { return CString("@@Category@@"); }
CString getVersion() const override { return CString("@@Version@@"); }
CString getStockItemName() const override { return CString("@@StockItemName@@"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_@@ClassName@@; }
IPluginObject* create() override { return new CBoxAlgorithm@@ClassName@@; }
@@BoxListenerCommentIn@@
IBoxListener* createBoxListener() const override { return new CBoxAlgorithm@@ClassName@@Listener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
@@BoxListenerCommentOut@@
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
@@Inputs@@
@@InputFlagCanModify@@
@@InputFlagCanAdd@@
@@Outputs@@
@@OutputFlagCanModify@@
@@OutputFlagCanAdd@@
@@Settings@@
@@SettingFlagCanModify@@
@@SettingFlagCanAdd@@
prototype.addFlag(OV_AttributeId_Box_FlagIsUnstable);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_@@ClassName@@Desc)
};
} // namespace @@Namespace@@
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,58 @@
#include "ovasCConfiguration@@ClassName@@.h"
using namespace OpenViBE;
using namespace /*OpenViBE::*/Kernel;
using namespace /*OpenViBE::*/AcquisitionServer;
/*_________________________________________________
Insert callback to specific widget here
Example with a button that launch a calibration of the device:
//Callback connected to a dedicated gtk button:
static void button_calibrate_pressed_cb(GtkButton* button, void* data)
{
CConfiguration@@ClassName@@* config = static_cast<CConfiguration@@ClassName@@*>(data);
config->buttonCalibratePressedCB();
}
//Callback actually called:
void CConfigurationGTecGUSBamp::buttonCalibratePressedCB()
{
// Connect to the hardware, ask for calibration, verify the return code, etc.
}
_________________________________________________*/
// If you added more reference attribute, initialize them here
CConfiguration@@ClassName@@::CConfiguration@@ClassName@@(IDriverContext& ctx, const char* gtkBuilderFilename)
: CConfigurationBuilder(gtkBuilderFilename), m_driverCtx(ctx) { }
bool CConfiguration@@ClassName@@::preConfigure()
{
if(! CConfigurationBuilder::preConfigure()) { return false; }
// Connect here all callbacks
// Example:
// g_signal_connect(gtk_builder_get_object(m_builder, "button_calibrate"), "pressed", G_CALLBACK(button_calibrate_pressed_cb), this);
// Insert here the pre-configure code.
// For example, you may want to check if a device is currently connected
// and if more than one are connected. Then you can list in a dedicated combo-box
// the device currently connected so the user can choose which one he wants to acquire from.
return true;
}
bool CConfiguration@@ClassName@@::postConfigure()
{
if(m_applyConfig)
{
// If the user pressed the "apply" button, you need to save the changes made in the configuration.
// For example, you can save the connection ID of the selected device:
// m_connectionID = <value-from-gtk-widget>
}
if(!CConfigurationBuilder::postConfigure()) { return false; } // normal header is filled (Subject ID, Age, Gender, channels, sampling frequency), ressources are realesed
return true;
}
@@ -0,0 +1,50 @@
#pragma once
#include "../ovasCConfigurationBuilder.h"
#include "ovasIDriver.h"
#include <gtk/gtk.h>
namespace OpenViBE
{
namespace AcquisitionServer
{
/**
* \class CConfiguration@@ClassName@@
* \author @@AuthorName@@ (@@CompanyName@@)
* \date @@Date@@
* \brief The CConfiguration@@ClassName@@ handles the configuration dialog specific to the @@DriverName@@ device.
*
* TODO: details
*
* \sa CDriver@@ClassName@@
*/
class CConfiguration@@ClassName@@ : public CConfigurationBuilder
{
public:
// you may have to add to your constructor some reference parameters
// for example, a connection ID:
//CConfiguration@@ClassName@@(IDriverContext& ctx, const char* gtkBuilderFilename, size_t& rConnectionId);
CConfiguration@@ClassName@@(IDriverContext& ctx, const char* gtkBuilderFilename);
virtual bool preConfigure();
virtual bool postConfigure();
protected:
IDriverContext& m_driverCtx;
private:
/*
* Insert here all specific attributes, such as a connection ID.
* use references to directly modify the corresponding attribute of the driver
* Example:
*/
// size_t& m_connectionID;
};
} //namespace AcquisitionServer
} //namespace OpenViBE
@@ -0,0 +1,149 @@
#include "ovasCDriver@@ClassName@@.h"
#include "ovasCConfiguration@@ClassName@@.h"
#include <toolkit/ovtk_all.h>
using namespace OpenViBE;
using namespace /*OpenViBE::*/AcquisitionServer;
using namespace /*OpenViBE::*/Kernel;
//___________________________________________________________________//
// //
CDriver@@ClassName@@::CDriver@@ClassName@@(IDriverContext& ctx)
:IDriver(ctx),m_settings("AcquisitionServer_Driver_@@ClassName@@", m_driverCtx.getConfigurationManager())
{
m_header.setSampling(@@Sampling@@);
m_header.setChannelCount(@@MaxChannel@@);
// The following class allows saving and loading driver settings from the acquisition server .conf file
m_settings.add("Header", &m_header);
// To save your custom driver settings, register each variable to the SettingsHelper
//m_settings.add("SettingName", &variable);
m_settings.load();
}
CDriver@@ClassName@@::~CDriver@@ClassName@@() { }
const char* CDriver@@ClassName@@::getName() { return "@@DriverName@@"; }
//___________________________________________________________________//
// //
bool CDriver@@ClassName@@::initialize(const size_t nSamplePerSentBlock, IDriverCallback& callback)
{
if(m_driverCtx.isConnected()) { return false; }
if(!m_header.isChannelCountSet()||!m_header.isSamplingSet()) { return false; }
// Builds up a buffer to store
// acquired samples. This buffer
// will be sent to the acquisition
// server later...
m_sample=new float[m_header.getChannelCount()*nSamplePerSentBlock];
if(!m_sample)
{
delete [] m_sample;
m_sample = nullptr;
return false;
}
// ...
// initialize hardware and get
// available header information
// from it
// Using for example the connection ID provided by the configuration (m_connectionID)
// ...
// Saves parameters
m_callback = &callback;
m_nSamplePerSentBlock = nSamplePerSentBlock;
return true;
}
bool CDriver@@ClassName@@::start()
{
if(!m_driverCtx.isConnected()) { return false; }
if(m_driverCtx.isStarted()) { return false; }
// ...
// request hardware to start
// sending data
// ...
return true;
}
bool CDriver@@ClassName@@::loop()
{
if(!m_driverCtx.isConnected()) { return false; }
if(!m_driverCtx.isStarted()) { return true; }
CStimulationSet stimSet;
// ...
// receive samples from hardware
// put them the correct way in the sample array
// whether the buffer is full, send it to the acquisition server
//...
m_callback->setSamples(m_sample);
// When your sample buffer is fully loaded,
// it is advised to ask the acquisition server
// to correct any drift in the acquisition automatically.
m_driverCtx.correctDriftSampleCount(m_driverCtx.getSuggestedDriftCorrectionSampleCount());
// ...
// receive events from hardware
// and put them the correct way in a CStimulationSet object
//...
m_callback->setStimulationSet(stimSet);
return true;
}
bool CDriver@@ClassName@@::stop()
{
if(!m_driverCtx.isConnected()) return false;
if(!m_driverCtx.isStarted()) return false;
// ...
// request the hardware to stop
// sending data
// ...
return true;
}
bool CDriver@@ClassName@@::uninitialize()
{
if(!m_driverCtx.isConnected()) return false;
if(m_driverCtx.isStarted()) return false;
// ...
// uninitialize hardware here
// ...
delete [] m_sample;
m_sample = nullptr;
m_callback = nullptr;
return true;
}
//___________________________________________________________________//
// //
bool CDriver@@ClassName@@::isConfigurable()
{
return true; // change to false if your device is not configurable
}
bool CDriver@@ClassName@@::configure()
{
// Change this line if you need to specify some references to your driver attribute that need configuration, e.g. the connection ID.
CConfiguration@@ClassName@@ config(m_driverCtx, Directories::getDataDir() + "/applications/acquisition-server/interface-@@ClassName@@.ui");
if(!config.configure(m_header)) { return false; }
m_settings.save();
return true;
}
@@ -0,0 +1,68 @@
#pragma once
#include "ovasIDriver.h"
#include "../ovasCHeader.h"
#include <openvibe/ov_all.h>
#include "../ovasCSettingsHelper.h"
#include "../ovasCSettingsHelperOperators.h"
namespace OpenViBE
{
namespace AcquisitionServer
{
/**
* \class CDriver@@ClassName@@
* \author @@AuthorName@@ (@@CompanyName@@)
* \date @@Date@@
* \brief The CDriver@@ClassName@@ allows the acquisition server to acquire data from a @@DriverName@@ device.
*
* TODO: details
*
* \sa CConfiguration@@ClassName@@
*/
class CDriver@@ClassName@@ : public IDriver
{
public:
CDriver@@ClassName@@(IDriverContext& ctx);
virtual ~CDriver@@ClassName@@();
virtual const char* getName();
virtual bool initialize(const size_t nSamplePerSentBlock, IDriverCallback& callback);
virtual bool uninitialize();
virtual bool start();
virtual bool stop();
virtual bool loop();
virtual bool isConfigurable();
virtual bool configure();
virtual const IHeader* getHeader() { return &m_header; }
virtual bool isFlagSet(const EDriverFlag flag) const { return flag==EDriverFlag::IsUnstable; }
protected:
SettingsHelper m_settings;
IDriverCallback* m_callback = nullptr;
// Replace this generic Header with any specific header you might have written
CHeader m_header;
size_t m_nSamplePerSentBlock = 0;
float* m_sample = nullptr;
private:
/*
* Insert here all specific attributes, such as USB port number or device ID.
* Example :
*/
// size_t m_connectionID = 0;
};
} //namespace AcquisitionServer
} //namespace OpenViBE
@@ -0,0 +1,323 @@
<?xml version="1.0"?>
<interface>
<object class="GtkAdjustment" id="adjustment1">
<property name="upper">100</property>
<property name="lower">0</property>
<property name="page_increment">10</property>
<property name="step_increment">1</property>
<property name="page_size">0</property>
<property name="value">18</property>
</object>
<object class="GtkAdjustment" id="adjustment2">
<property name="upper">100</property>
<property name="lower">0</property>
<property name="page_increment">10</property>
<property name="step_increment">1</property>
<property name="page_size">0</property>
<property name="value">0</property>
</object>
<object class="GtkAdjustment" id="adjustment3">
<property name="upper">@@MaxChannel@@</property>
<property name="lower">@@MinChannel@@</property>
<property name="page_increment">10</property>
<property name="step_increment">1</property>
<property name="page_size">0</property>
<property name="value">@@MaxChannel@@</property>
</object>
<object class="GtkListStore" id="model1">
<columns>
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">unspecified</col>
</row>
<row>
<col id="0" translatable="yes">female</col>
</row>
<row>
<col id="0" translatable="yes">male</col>
</row>
<row>
<col id="0" translatable="yes">unknown</col>
</row>
</data>
</object>
<object class="GtkListStore" id="model2">
<columns>
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">@@SamplingFrequencyList@@</col>
</row>
</data>
</object>
<!-- interface-requires gtk+ 2.6 -->
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkDialog" id="openvibe-acquisition-server-settings">
<property name="border_width">5</property>
<property name="title" translatable="yes">Device configuration</property>
<property name="window_position">center</property>
<property name="type_hint">dialog</property>
<property name="gravity">center</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel" id="label_title">
<property name="visible">True</property>
<property name="label" translatable="yes">@@DriverName@@</property>
<property name="justify">center</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkHSeparator" id="hseparator">
<property name="visible">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox">
<property name="visible">True</property>
<property name="border_width">8</property>
<property name="spacing">8</property>
<child>
<object class="GtkHBox" id="hbox">
<property name="visible">True</property>
<property name="spacing">8</property>
<child>
<object class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_rows">5</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkComboBox" id="combobox_gender">
<property name="visible">True</property>
<property name="model">model1</property>
<child>
<object class="GtkCellRendererText" id="renderer1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton_age">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment1</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton_identifier">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment2</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_sampling_frequency">
<property name="visible">True</property>
<property name="label" translatable="yes">Sampling frequency :</property>
<property name="justify">right</property>
<property name="single_line_mode">True</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_number_of_channels">
<property name="visible">True</property>
<property name="label" translatable="yes">Number of channels :</property>
<property name="justify">right</property>
<property name="single_line_mode">True</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_gender">
<property name="visible">True</property>
<property name="label" translatable="yes">Gender :</property>
<property name="justify">right</property>
<property name="single_line_mode">True</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_age">
<property name="visible">True</property>
<property name="label" translatable="yes">Age :</property>
<property name="justify">right</property>
<property name="single_line_mode">True</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_identifier">
<property name="visible">True</property>
<property name="label" translatable="yes">Identifier :</property>
<property name="justify">right</property>
<property name="single_line_mode">True</property>
</object>
</child>
<child>
<object class="GtkComboBox" id="combobox_sampling_frequency">
<property name="visible">True</property>
<property name="active">0</property>
<property name="model">model2</property>
<child>
<object class="GtkCellRendererText" id="renderer2"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton_number_of_channels">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment3</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_change_channel_names">
<property name="label" translatable="yes">Change channel names</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkHSeparator" id="hseparator1">
<property name="visible">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button_apply">
<property name="label">gtk-apply</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_cancel">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-10">button_apply</action-widget>
<action-widget response="-6">button_cancel</action-widget>
</action-widgets>
</object>
</interface>
@@ -0,0 +1,51 @@
******************************************************
* Thanks for using the OpenViBE Skeleton Generator ! *
******************************************************
File generation completed
[@@Date@@]
-------------------------
The generator produced the following files:
The Box class:
- ovpCBoxAlgorithm@@ClassName@@.h
- ovpCBoxAlgorithm@@ClassName@@.cpp
Please put these files in your local repository, in the project of your choice (e.g. Signal Processing or Classification)
[openvibe-repository]/contrib/plugins/[plugin-project]/src/[my-box-folder]
You may have to change the file ovpCBoxAlgorithm@@ClassName@@.h to make it find the included file ovp_defines.h, whose path is related to the project used.
Don't forget to declare your box in ovp_main.cpp, in order to make it available in the Designer.
Look in one of the ovp_main.cpp file, you will find examples of such declarations (#include the header, then OVP_Declare_New macro).
This look something like this:
#include "[my-box-folder]/ovpCBoxAlgorithm@@ClassName@@.h"
...
OVP_Declare_Begin();
...
OVP_Declare_New(OpenViBE::Plugins::@@Namespace@@::CBoxAlgorithm@@ClassName@@Desc);
...
OVP_Declare_End()
If your box doesn't appear in the designer, maybe it's because you cannot see Unstable Boxes.
Try to set your configuration file (openvibe.conf on windows / .openviberc on Linux) with the following token :
>>>>>
Designer_ShowUnstable = true
>>>>>
For more information about implementing algorithms and boxes to fill your skeleton, please read the official tutorial:
http://openvibe.inria.fr/tutorial-1-implementing-a-signal-processing-box/
Feel free to propose your contribution on the forum !
http://openvibe.inria.fr/forum/
Enjoy OpenViBE !
- The development team -
@@ -0,0 +1,42 @@
******************************************************
* Thanks for using the OpenViBE Skeleton Generator ! *
******************************************************
File generation completed
[@@Date@@]
-------------------------
WARNING:
Writing a new driver for an EEG device is often dependent on hardware specifications, such as OS compatibility
or communication protocol. The generator gives you only the basic skeletons for easy integration with OpenViBE,
please refer to your device specifications (API, protocol description, etc.) for the next steps...
The generator produced the following files:
The Configuration and Driver classes:
- ovasCConfiguration@@ClassName@@.h
- ovasCConfiguration@@ClassName@@.cpp
- ovasCDriver@@ClassName@@.h
- ovasCDriver@@ClassName@@.cpp
You can put these files here in your local repository:
[openvibe-repository]/contrib/plugins/server-drivers/[my-device]/src/
The glade interface:
- interface-@@ClassName@@.glade
You can put this file in here in your local repository:
[openvibe-repository]/contrib/plugins/server-drivers/[my-device]/share/
Don't forget to declare your driver to the Acquisition Server application.
This happens in "./contrib/common/contribAcquisitionServer.inl", there you
will find examples of such declarations. You also need to register the source
files to CMake, modifying the corresponding "contribAcquisitionServer.cmake".
For more information about building a new driver and filling your skeleton, please read the official tutorial:
http://openvibe.inria.fr/tutorial-creating-a-new-driver-for-the-acquisition-server/
Feel free to propose your contribution on the forum !
http://openvibe.inria.fr/forum/
Enjoy OpenViBE !
- The development team -
@@ -0,0 +1,14 @@
######################################################################################
## OpenViBE configuration file, application specific values
##
## - The file consists of a list of "token name = token value"
## - Whatever space / tabulation at the begining or end of a line is removed
## - Comments start with #
## - Lines ending with \ continue on the next line (all ending \ are removed)
## - On Windows, use / in paths as \ is reserved
## - You can use ${token name} in a token value
## - You can use $Environment{env name} in a token value to get an environment variable
######################################################################################
CustomConfiguration = ${CustomConfigurationPrefix${OperatingSystem}}${CustomConfigurationSuffix${OperatingSystem}}
CustomConfigurationApplication = ${CustomConfigurationPrefix${OperatingSystem}}-${ApplicationName}${CustomConfigurationSuffix${OperatingSystem}}