init
This commit is contained in:
+40
@@ -0,0 +1,40 @@
|
||||
|
||||
IF(OV_DISABLE_GTK)
|
||||
MESSAGE(STATUS "Skipping Skeleton Generator, no GTK")
|
||||
RETURN()
|
||||
ENDIF(OV_DISABLE_GTK)
|
||||
|
||||
PROJECT(openvibe-skeleton-generator)
|
||||
|
||||
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
|
||||
SET(PROJECT_VERSION ${OV_GLOBAL_VERSION_STRING})
|
||||
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.inl)
|
||||
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_FILES})
|
||||
SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${APP_FOLDER})
|
||||
|
||||
# ---------------------------------
|
||||
INCLUDE("FindOpenViBE")
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
INCLUDE("FindOpenViBEToolkit")
|
||||
INCLUDE("FindOpenViBEModuleEBML")
|
||||
INCLUDE("FindOpenViBEModuleFS")
|
||||
INCLUDE("FindThirdPartyGTK")
|
||||
INCLUDE("FindThirdPartyBoost")
|
||||
INCLUDE("FindThirdPartyBoost_Thread")
|
||||
INCLUDE("FindThirdPartyBoost_Regex")
|
||||
|
||||
# ----------------------
|
||||
# Generate launch script
|
||||
# ----------------------
|
||||
OV_INSTALL_LAUNCH_SCRIPT(SCRIPT_PREFIX "${PROJECT_NAME}" EXECUTABLE_NAME "${PROJECT_NAME}")
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
|
||||
INSTALL(DIRECTORY share/ DESTINATION ${DIST_DATADIR}/openvibe/applications/skeleton-generator)
|
||||
+147
@@ -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;
|
||||
}
|
||||
+148
@@ -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;
|
||||
}
|
||||
+149
@@ -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
|
||||
+58
@@ -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;
|
||||
}
|
||||
+50
@@ -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
|
||||
|
||||
|
||||
+149
@@ -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;
|
||||
}
|
||||
+68
@@ -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
|
||||
|
||||
|
||||
+3226
File diff suppressed because it is too large
Load Diff
+323
@@ -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>
|
||||
+51
@@ -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 -
|
||||
+42
@@ -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 -
|
||||
+14
@@ -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}}
|
||||
+1570
File diff suppressed because it is too large
Load Diff
+138
@@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovsgCSkeletonGenerator.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace SkeletonGenerator {
|
||||
class CBoxAlgorithmSkeletonGenerator final : public CSkeletonGenerator
|
||||
{
|
||||
public:
|
||||
|
||||
CBoxAlgorithmSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder) : CSkeletonGenerator(ctx, builder) { }
|
||||
~CBoxAlgorithmSkeletonGenerator() override { }
|
||||
|
||||
bool initialize() override;
|
||||
bool save(const std::string& filename) override;
|
||||
bool load(const std::string& filename) override;
|
||||
void getCurrentParameters() override;
|
||||
|
||||
// Box Description
|
||||
std::string m_Name, m_Version, m_ClassName, m_Category, m_ShortDesc, m_DetailedDesc;
|
||||
std::string m_GtkStockItemName;
|
||||
int m_GtkStockItemIdx = 0;
|
||||
|
||||
struct SIOS
|
||||
{
|
||||
std::string name, type, typeID, defaultValue;
|
||||
};
|
||||
|
||||
// Inputs
|
||||
bool m_CanModifyInputs = false, m_CanAddInputs = false;
|
||||
std::vector<SIOS> m_Inputs;
|
||||
// Outputs
|
||||
bool m_CanModifyOutputs = false, m_CanAddOutputs = false;
|
||||
std::vector<SIOS> m_Outputs;
|
||||
// Settings
|
||||
bool m_CanModifySettings = false, m_CanAddSettings = false;
|
||||
std::vector<SIOS> m_Settings;
|
||||
|
||||
//Algorithms
|
||||
std::vector<std::string> m_Algorithms; // the algorithm selected by user
|
||||
// Can be made non-const after '= false' produces working code
|
||||
static const bool USE_CODEC_TOOLKIT = true; // use or not the codec toolkit for encoder and decoder algorithms
|
||||
//the map between algorithm and corresponding header declaration (all variables algo/input/output).
|
||||
std::map<std::string, std::string> m_AlgoDeclaration;
|
||||
//the map between algorithm and corresponding initialisation
|
||||
std::map<std::string, std::string> m_AlgoInitialisations;
|
||||
//the map between algorithm and corresponding initialisation of ref targets
|
||||
std::map<std::string, std::string> m_AlgoInitialisationReferenceTargets;
|
||||
//the map between algorithm and corresponding uninitialisation
|
||||
std::map<std::string, std::string> m_AlgoUninitialisations;
|
||||
|
||||
// Box Listener
|
||||
bool m_UseBoxListener = false;
|
||||
// input
|
||||
bool m_HasOnInputAdded = false;
|
||||
bool m_HasOnInputRemoved = false;
|
||||
bool m_HasOnInputTypeChanged = false;
|
||||
bool m_HasOnInputNameChanged = false;
|
||||
bool m_HasOnInputConnected = false;
|
||||
bool m_HasOnInputDisconnected = false;
|
||||
// output
|
||||
bool m_HasOnOutputAdded = false;
|
||||
bool m_HasOnOutputRemoved = false;
|
||||
bool m_HasOnOutputTypeChanged = false;
|
||||
bool m_HasOnOutputNameChanged = false;
|
||||
bool m_HasOnOutputConnected = false;
|
||||
bool m_HasOnOutputDisconnected = false;
|
||||
// setting
|
||||
bool m_HasOnSettingAdded = false;
|
||||
bool m_HasOnSettingRemoved = false;
|
||||
bool m_HasOnSettingTypeChanged = false;
|
||||
bool m_HasOnSettingNameChanged = false;
|
||||
bool m_HasOnSettingDefaultValueChanged = false;
|
||||
bool m_HasOnSettingValueChanged = false;
|
||||
|
||||
bool m_HasProcessInput = false;
|
||||
bool m_HasProcessClock = false;
|
||||
bool m_HasProcessMessage = false;
|
||||
uint32_t m_ClockFrequency = 0;
|
||||
|
||||
void buttonCheckCB();
|
||||
void buttonOkCB();
|
||||
void toggleListenerCheckbuttonsStateCB(bool state) const;
|
||||
void buttonTooltipCB(GtkButton* button);
|
||||
void buttonExitCB();
|
||||
|
||||
void buttonAddInputCB() const;
|
||||
void buttonAddOutputCB() const;
|
||||
void buttonAddSettingCB() const;
|
||||
void buttonAddAlgorithmCB() const;
|
||||
void buttonRemoveGeneric(const char* buttonName) const;
|
||||
|
||||
void algorithmSelectedCB(int index);
|
||||
void setSensitivity(const char* widgetName, bool isActive) const;
|
||||
|
||||
private:
|
||||
|
||||
Kernel::ILogManager& getLogManager() const override { return m_kernelCtx.getLogManager(); }
|
||||
Kernel::IErrorManager& getErrorManager() const override { return m_kernelCtx.getErrorManager(); }
|
||||
|
||||
static std::string getRandomIdentifierString() { return CIdentifier::random().str(); }
|
||||
|
||||
// Sanity checks that a string is not empty or consist of spaces
|
||||
static bool isStringValid(const std::string& str) { return !str.empty() && str.find_first_not_of(' ') != std::string::npos; }
|
||||
|
||||
void clearStore(const char* name) const;
|
||||
void addDialogButttons(const char* name) const;
|
||||
void setEntryToConfigValue(const char* name, const char* token) const;
|
||||
void setActiveFromConf(const char* name, const char* token) const;
|
||||
void setActiveFromConfTog(const char* name, const char* token) const;
|
||||
const gchar* getText(const char* name) const;
|
||||
void addCollectionToTree(const char* treeName, const std::vector<std::string>& collection) const;
|
||||
void fillCollection(const char* treeName, std::vector<SIOS>& collection) const;
|
||||
bool isActive(char* name) const;
|
||||
|
||||
std::map<GtkButton*, std::string> m_tooltips;
|
||||
std::vector<std::string> m_typeCorrespondances;
|
||||
};
|
||||
|
||||
class CDummyAlgoProto final : public Kernel::IAlgorithmProto
|
||||
{
|
||||
public:
|
||||
std::map<std::string, Kernel::EParameterType> m_Inputs, m_Outputs;
|
||||
std::vector<std::string> m_InputTriggers, m_OutputTriggers;
|
||||
|
||||
bool addInputParameter(const CIdentifier& id, const CString& name, Kernel::EParameterType typeID,
|
||||
const CIdentifier& subTypeID = CIdentifier::undefined()) override;
|
||||
bool addOutputParameter(const CIdentifier& id, const CString& name, Kernel::EParameterType typeID,
|
||||
const CIdentifier& subTypeID = CIdentifier::undefined()) override;
|
||||
bool addInputTrigger(const CIdentifier& id, const CString& name) override;
|
||||
bool addOutputTrigger(const CIdentifier& id, const CString& name) override;
|
||||
|
||||
CIdentifier getClassIdentifier() const override { return CIdentifier::undefined(); }
|
||||
};
|
||||
} // namespace SkeletonGenerator
|
||||
} // namespace OpenViBE
|
||||
+504
@@ -0,0 +1,504 @@
|
||||
#include "ovsgCDriverSkeletonGenerator.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace SkeletonGenerator {
|
||||
//-----------------------------------------------------------------------
|
||||
static void CheckCB(GtkButton* /*button*/, void* data) { static_cast<CDriverSkeletonGenerator*>(data)->buttonCheckCB(); }
|
||||
static void TooltipCB(GtkButton* button, void* data) { static_cast<CDriverSkeletonGenerator*>(data)->buttonTooltipCB(button); }
|
||||
static void OkCB(GtkButton* /*button*/, void* data) { static_cast<CDriverSkeletonGenerator*>(data)->buttonOkCB(); }
|
||||
|
||||
static void ExitCB(GtkButton* /*button*/, void* data)
|
||||
{
|
||||
static_cast<CDriverSkeletonGenerator*>(data)->buttonExitCB();
|
||||
gtk_exit(0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void CDriverSkeletonGenerator::buttonExitCB()
|
||||
{
|
||||
getCommonParameters();
|
||||
getCurrentParameters();
|
||||
if (!cleanConfigurationFile(m_configFile)) { return; }
|
||||
saveCommonParameters(m_configFile);
|
||||
save(m_configFile);
|
||||
|
||||
getLogManager() << Kernel::LogLevel_Info << "All entries saved in [" << m_configFile << "]. Exiting.\n";
|
||||
}
|
||||
|
||||
void CDriverSkeletonGenerator::buttonCheckCB()
|
||||
{
|
||||
//Author and Company
|
||||
getCommonParameters();
|
||||
getCurrentParameters();
|
||||
|
||||
getLogManager() << Kernel::LogLevel_Info << "Checking values... \n";
|
||||
|
||||
bool success = true;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "----- STATUS -----\n";
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
//::GtkWidget * driverName = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_driver_name"));
|
||||
//m_DriverName = gtk_entry_get_text(GTK_ENTRY(driverName));
|
||||
const boost::regex regExpDriverName("([a-z]|[A-Z]|[0-9])+([a-z]|[A-Z]|[0-9]|[ \t\r\n]|[\\.-_\\(\\)])*", boost::regex::perl);
|
||||
if (regex_match(std::string(m_DriverName), regExpDriverName) == false)
|
||||
{
|
||||
OV_WARNING_K("-- Driver Name: INVALID");
|
||||
success = false;
|
||||
ss << "[FAILED] Invalid driver name. Please use only characters (lower or uppercase) and numbers (blanck allowed).\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Info << "-- Driver Name: VALID (" << m_DriverName << ")\n";
|
||||
ss << "[ OK ] Valid driver name.\n";
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
//::GtkWidget * className = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_class_name"));
|
||||
//m_ClassName = gtk_entry_get_text(GTK_ENTRY(className));
|
||||
const boost::regex regExpClassName("([a-z]|[A-Z]|[0-9])+", boost::regex::perl);
|
||||
if (regex_match(std::string(m_ClassName), regExpClassName) == false)
|
||||
{
|
||||
OV_WARNING_K("-- Class Name: INVALID");
|
||||
success = false;
|
||||
ss << "[FAILED] Invalid class name. Please use only characters (lower or uppercase) and numbers (no blanck allowed).\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Info << "-- Class Name: VALID (" << m_ClassName << ")\n";
|
||||
ss << "[ OK ] Valid class name.\n";
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
GtkWidget* spinMinChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_min_channel"));
|
||||
//m_MinChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMinChannel)))).c_str();
|
||||
GtkWidget* spinMaxChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_max_channel"));
|
||||
//m_MaxChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMaxChannel)))).c_str();
|
||||
if (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMinChannel)) > gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMaxChannel)))
|
||||
{
|
||||
OV_WARNING_K(Kernel::LogLevel_Warning << "-- Channels: INVALID");
|
||||
success = false;
|
||||
ss << "[FAILED] Invalid channel count. Be sure that Min <= Max.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Info << "-- Channels: VALID (" << m_MinChannel << "/" << m_MaxChannel << ")\n";
|
||||
ss << "[ OK ] Valid channel count.\n";
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
/*::GtkWidget * sf = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_sampling_frequencies"));
|
||||
CString samplings = gtk_entry_get_text(GTK_ENTRY(sf));
|
||||
*/
|
||||
const boost::regex regExpSamplings("(([1-9][0-9]*);)*([1-9][0-9]*)", boost::regex::perl);
|
||||
if (regex_match(m_Samplings, regExpSamplings) == false)
|
||||
{
|
||||
OV_WARNING_K("-- Sampling frequencies: INVALID");
|
||||
success = false;
|
||||
ss << "[FAILED] Invalid sampling frequencies. Please use only whole numbers separated with ';' (no blanck allowed).\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Maximum 16 frequencies
|
||||
size_t nSampling = 0;
|
||||
size_t freq;
|
||||
std::stringstream tmp(m_Samplings);
|
||||
m_SamplingSeparate.clear();
|
||||
while (tmp >> freq && nSampling < 16)
|
||||
{
|
||||
m_SamplingSeparate.push_back(std::to_string(freq));
|
||||
if (tmp.peek() == ';') { tmp.ignore(); }
|
||||
nSampling++;
|
||||
}
|
||||
|
||||
getLogManager() << Kernel::LogLevel_Info << "-- Sampling frequencies: VALID\n";
|
||||
for (const auto& s : m_SamplingSeparate) { std::cout << "- " << s << " Hz\n"; }
|
||||
|
||||
ss << "[ OK ] " << nSampling << " valid sampling frequencie(s).\n";
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
/*::GtkWidget * fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
|
||||
char * directory = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fileChooser));
|
||||
m_directory = CString(directory);
|
||||
g_free(directory);*/
|
||||
|
||||
#ifdef TARGET_OS_Windows
|
||||
const std::string space("%20");
|
||||
if (m_directory.rfind(space) != std::string::npos)
|
||||
{
|
||||
ss << "[FAILED] Invalid destination folder :" << m_directory << ".\n";
|
||||
getLogManager() << Kernel::LogLevel_Error << "Invalid destination folder :" << m_directory << ".\n";
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Info << "-- Target directory: " << m_directory << "\n";
|
||||
ss << "[ OK ] Valid target directory: " << m_directory << "\n";
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
GtkWidget* textview = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-tooltips-textview"));
|
||||
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
|
||||
if (success)
|
||||
{
|
||||
ss << "----- SUCCESS -----\nPress OK to generate the files. If you want to modify your choice(s), please press the \"Check\" button again.";
|
||||
GtkWidget* buttonOk = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-ok-button"));
|
||||
gtk_widget_set_sensitive(buttonOk, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "----- PROCESS FAILED -----\nModify your choices and press the \"Check\" button again.";
|
||||
GtkWidget* buttonOk = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-ok-button"));
|
||||
gtk_widget_set_sensitive(buttonOk, false);
|
||||
}
|
||||
|
||||
gtk_text_buffer_set_text(buffer, ss.str().c_str(), -1);
|
||||
}
|
||||
|
||||
void CDriverSkeletonGenerator::buttonOkCB()
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Info << "Generating files... \n";
|
||||
std::string log = "Generating files...\n";
|
||||
|
||||
bool success = true;
|
||||
|
||||
const std::string date = getDate();
|
||||
|
||||
// we construct the map of substitutions
|
||||
std::map<std::string, std::string> substitutions;
|
||||
substitutions["@@AuthorName@@"] = m_author;
|
||||
substitutions["@@CompanyName@@"] = m_company;
|
||||
substitutions["@@Date@@"] = date;
|
||||
substitutions["@@ClassName@@"] = m_ClassName;
|
||||
substitutions["@@DriverName@@"] = m_DriverName;
|
||||
substitutions["@@MinChannel@@"] = m_MinChannel;
|
||||
substitutions["@@MaxChannel@@"] = m_MaxChannel;
|
||||
substitutions["@@SamplingFrequency@@"] = m_SamplingSeparate[0];
|
||||
|
||||
GtkWidget* textview = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-tooltips-textview"));
|
||||
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
// driver.h
|
||||
std::string dst = m_directory + "/ovasCDriver" + m_ClassName + ".h";
|
||||
std::string tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/driver.h-skeleton").toASCIIString();
|
||||
|
||||
if (!this->generate(tmplate, dst, substitutions, log))
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
|
||||
success = false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
// driver.cpp
|
||||
dst = m_directory + "/ovasCDriver" + m_ClassName + ".cpp";
|
||||
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/driver.cpp-skeleton").toASCIIString();
|
||||
|
||||
if (!this->generate(tmplate, dst, substitutions, log))
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
|
||||
success = false;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
// config.h
|
||||
dst = m_directory + "/ovasCConfiguration" + m_ClassName + ".h";
|
||||
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/configuration.h-skeleton").toASCIIString();
|
||||
|
||||
if (!this->generate(tmplate, dst, substitutions, log))
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
|
||||
success = false;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
// config.cpp
|
||||
dst = m_directory + "/ovasCConfiguration" + m_ClassName + ".cpp";
|
||||
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/configuration.cpp-skeleton").toASCIIString();
|
||||
|
||||
if (!this->generate(tmplate, dst, substitutions, log))
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
|
||||
success = false;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
// interface.ui
|
||||
dst = m_directory + "/interface-" + m_ClassName + ".ui";
|
||||
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/interface.ui-skeleton").toASCIIString();
|
||||
|
||||
if (!this->generate(tmplate, dst, substitutions, log))
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
|
||||
success = false;
|
||||
}
|
||||
// the following substitution is done in a .ui file, and not in a cpp file.
|
||||
// The SED primitive immplemented do not cover that case, and some typo problem happen with the character "
|
||||
const std::string pattern("@@SamplingFrequencyList@@");
|
||||
std::string substitute;
|
||||
for (auto it = m_SamplingSeparate.begin(); it != m_SamplingSeparate.end();)
|
||||
{
|
||||
substitute += (*it++);
|
||||
if (it != m_SamplingSeparate.end()) { substitute += "<\\/col><\\/row><row><col id=\\\"0\\\" translatable=\\\"yes\\\">"; }
|
||||
}
|
||||
success &= regexReplace(dst, pattern, substitute, "");
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
// readme-driver.txt
|
||||
dst = m_directory + "/README.txt";
|
||||
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/readme-driver.txt-skeleton");
|
||||
|
||||
if (!this->generate(tmplate, dst, substitutions, log))
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
|
||||
success = false;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
if (success)
|
||||
{
|
||||
success &= cleanConfigurationFile(m_configFile);
|
||||
success &= saveCommonParameters(m_configFile);
|
||||
success &= save(m_configFile);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
log += "Generation process did not completly succeed. Some files may have not been produced.\n";
|
||||
OV_WARNING_K("Generation process did not completly succeed. Some files may have not been produced.");
|
||||
}
|
||||
else
|
||||
{
|
||||
log += "Generation process successful. All information saved in [" + m_configFile + "]\nPlease read the file [README.txt] !\n";
|
||||
getLogManager() << Kernel::LogLevel_Info << "Generation process successful. All information saved in [" << m_configFile << "]\n";
|
||||
}
|
||||
|
||||
// Launch the browser to display the produced files
|
||||
const std::string browser = m_kernelCtx.getConfigurationManager().expand("${Designer_WebBrowserCommand_${OperatingSystem}}").toASCIIString();
|
||||
|
||||
#ifdef TARGET_OS_Windows
|
||||
const std::string browserCmd = browser + " file:///" + m_directory; //otherwise the browser does not find the directory (problem with / and \ char)
|
||||
#else
|
||||
const std::string browserCmd = browser + " \"" + m_directory + "\"";
|
||||
#endif
|
||||
|
||||
if (system(browserCmd.c_str())) { }
|
||||
|
||||
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
|
||||
}
|
||||
|
||||
void CDriverSkeletonGenerator::buttonTooltipCB(GtkButton* button)
|
||||
{
|
||||
const EWidgetName widgetName = m_widgetNames[button];
|
||||
|
||||
GtkWidget* textview = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-tooltips-textview"));
|
||||
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
|
||||
|
||||
if (widgetName == EWidgetName::DriverName)
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer,
|
||||
"Driver Name: \nThis name will be the one displayed in the Acquisition Server selection combobox.\nUsually, the driver is named according to the EEG device (with precisions such as a version number).\n------\nExample: OpenEEG Modular EEG (P2)\n\n\n",
|
||||
-1);
|
||||
}
|
||||
else if (widgetName == EWidgetName::ClassName)
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer,
|
||||
"Class Name: \nThis name will be used to generate all source and GUI files.\nYou should choose a class name close to the device name (no blank allowed !).\n------\nExample: OpenEEGModularEEG will generate\n - ovasCDriverOpenEEGModularEEG.h/.cpp, the driver skeleton \n - ovasCConfigurationOpenEEGModularEEG.h/.cpp, the configuration class skeleton\n - interface-OpenEEG-ModularEEG.ui, the GUI description file",
|
||||
-1);
|
||||
}
|
||||
else if (widgetName == EWidgetName::ChannelCount)
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer,
|
||||
"Channel count: \nEnter in the two fields the minimum and maximum number of channels the device is capable of.\nOf course you can still change it later in the source code.\n------\nExample: Min(1) Max(16)\n\n\n",
|
||||
-1);
|
||||
}
|
||||
else if (widgetName == EWidgetName::Sampling)
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer,
|
||||
"Sampling frequencies: \nEnter in the text field the sampling frequencies your device is capable of.\nYou can specify a list of defined frequencies (value separator ';').\n------\nExample:\n\"128;256;512\" for three defined frequencies.\n\n",
|
||||
-1);
|
||||
}
|
||||
else if (widgetName == EWidgetName::Directory)
|
||||
{
|
||||
gtk_text_buffer_set_text(buffer,
|
||||
"Target directory: \nEnter the destination directory in which all files will be generated. \nAny existing files will be overwritten.\n------\nExample: ~/skeleton-generator/foobar-driver/\n\n\n",
|
||||
-1);
|
||||
}
|
||||
else { }
|
||||
}
|
||||
|
||||
bool CDriverSkeletonGenerator::initialize()
|
||||
{
|
||||
GtkWidget* driver = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-window"));
|
||||
|
||||
// Buttons and signals
|
||||
GtkWidget* buttonCheck = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-check-button"));
|
||||
GtkWidget* buttonOk = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-ok-button"));
|
||||
|
||||
g_signal_connect(buttonCheck, "pressed", G_CALLBACK(CheckCB), this);
|
||||
g_signal_connect(buttonOk, "pressed", G_CALLBACK(OkCB), this);
|
||||
|
||||
////target directory
|
||||
//::GtkWidget * fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
|
||||
//CString directory = m_kernelContext.getConfigurationManager().expand("${SkeletonGenerator_TargetDirectory}");
|
||||
//if(!gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fileChooser), directory.c_str()))
|
||||
//{
|
||||
// gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fileChooser),"..");
|
||||
//}
|
||||
|
||||
|
||||
// Tooltips buttons and signal
|
||||
GtkButton* buttonDriverName = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-driver-name-tooltip-button"));
|
||||
GtkButton* buttonClassName = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-class-name-tooltip-button"));
|
||||
GtkButton* buttonChannelCount = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-channel-count-tooltip-button"));
|
||||
GtkButton* buttonSampling = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-sampling-frequencies-tooltip-button"));
|
||||
GtkButton* buttonDirectory = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-target-directory-tooltip-button"));
|
||||
|
||||
m_widgetNames[buttonDriverName] = EWidgetName::DriverName;
|
||||
m_widgetNames[buttonClassName] = EWidgetName::ClassName;
|
||||
m_widgetNames[buttonChannelCount] = EWidgetName::ChannelCount;
|
||||
m_widgetNames[buttonSampling] = EWidgetName::Sampling;
|
||||
m_widgetNames[buttonDirectory] = EWidgetName::Directory;
|
||||
|
||||
g_signal_connect(buttonDriverName, "pressed", G_CALLBACK(TooltipCB), this);
|
||||
g_signal_connect(buttonClassName, "pressed", G_CALLBACK(TooltipCB), this);
|
||||
g_signal_connect(buttonChannelCount, "pressed", G_CALLBACK(TooltipCB), this);
|
||||
g_signal_connect(buttonSampling, "pressed", G_CALLBACK(TooltipCB), this);
|
||||
g_signal_connect(buttonDirectory, "pressed", G_CALLBACK(TooltipCB), this);
|
||||
|
||||
//Close with X and "cancel" button
|
||||
g_signal_connect(G_OBJECT(driver), "delete_event", G_CALLBACK(gtk_exit), nullptr);
|
||||
GtkWidget* buttonCancel = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-cancel-button"));
|
||||
g_signal_connect(buttonCancel, "pressed", G_CALLBACK(ExitCB), this);
|
||||
|
||||
//load everything from file
|
||||
load(m_configFile);
|
||||
|
||||
gtk_widget_show_all(driver);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDriverSkeletonGenerator::save(const std::string& filename)
|
||||
{
|
||||
std::ofstream file;
|
||||
file.open(filename, std::ios::app | std::ios::binary);
|
||||
OV_ERROR_UNLESS_KRF(file.is_open(), "Saving the driver entries in [" << m_configFile << "] failed !", Kernel::ErrorType::BadFileWrite);
|
||||
|
||||
file << "# ----------------------DRIVER-------------------------\n";
|
||||
std::string directory(m_directory);
|
||||
for (auto it = directory.begin(); it < directory.end(); ++it) { if ((*it) == '\\') { directory.replace(it, it + 1, 1, '/'); } }
|
||||
|
||||
file << "SkeletonGenerator_Driver_DriverName = " << m_DriverName << std::endl;
|
||||
file << "SkeletonGenerator_Driver_ClassName = " << m_ClassName << std::endl;
|
||||
file << "SkeletonGenerator_Driver_MinChannel = " << m_MinChannel << std::endl;
|
||||
file << "SkeletonGenerator_Driver_MaxChannel = " << m_MaxChannel << std::endl;
|
||||
file << "SkeletonGenerator_Driver_SamplingFrequencies = " << m_Samplings << std::endl;
|
||||
file << "SkeletonGenerator_Driver_TargetDirectory = " << directory << std::endl;
|
||||
file << "# -----------------------------------------------------" << std::endl;
|
||||
file.close();
|
||||
getLogManager() << Kernel::LogLevel_Info << "Driver entries saved in [" << m_configFile << "]\n";
|
||||
|
||||
m_configFileLoaded = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDriverSkeletonGenerator::load(const std::string& filename)
|
||||
{
|
||||
if (!m_configFileLoaded && !m_kernelCtx.getConfigurationManager().addConfigurationFromFile(filename.c_str()))
|
||||
{
|
||||
OV_WARNING_K("Driver: Configuration file [" << filename << "] could not be loaded. It will be automatically generated after first use.");
|
||||
return false;
|
||||
}
|
||||
|
||||
GtkWidget* driverName = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_driver_name"));
|
||||
gtk_entry_set_text(GTK_ENTRY(driverName), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_DriverName}"));
|
||||
|
||||
GtkWidget* className = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_class_name"));
|
||||
gtk_entry_set_text(GTK_ENTRY(className), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_ClassName}"));
|
||||
|
||||
GtkWidget* minChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_min_channel"));
|
||||
gtk_spin_button_set_value(
|
||||
GTK_SPIN_BUTTON(minChannel), double(m_kernelCtx.getConfigurationManager().expandAsInteger("${SkeletonGenerator_Driver_MinChannel}")));
|
||||
|
||||
GtkWidget* maxChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_max_channel"));
|
||||
gtk_spin_button_set_value(
|
||||
GTK_SPIN_BUTTON(maxChannel), double(m_kernelCtx.getConfigurationManager().expandAsInteger("${SkeletonGenerator_Driver_MaxChannel}")));
|
||||
|
||||
GtkWidget* sf = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_sampling_frequencies"));
|
||||
gtk_entry_set_text(GTK_ENTRY(sf), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_SamplingFrequencies}"));
|
||||
|
||||
GtkWidget* fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
|
||||
|
||||
// if the user specified a target directory, it has full priority
|
||||
std::string directory = m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_TargetDirectory}").toASCIIString();
|
||||
#ifdef TARGET_OS_Linux
|
||||
bool needFilePrefix = false;
|
||||
#endif
|
||||
if (!directory.empty())
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Debug << "Target dir user [" << directory << "]\n";
|
||||
#ifdef TARGET_OS_Linux
|
||||
needFilePrefix = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//previous entry
|
||||
directory = m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_TargetDirectory}");
|
||||
if (!directory.empty())
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Debug << "Target previous [" << directory << "]\n";
|
||||
#ifdef TARGET_OS_Linux
|
||||
needFilePrefix = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//default path = dist
|
||||
getLogManager() << Kernel::LogLevel_Debug << "Target default [dist]\n";
|
||||
#ifdef TARGET_OS_Linux
|
||||
directory = std::string(gtk_file_chooser_get_current_folder_uri(GTK_FILE_CHOOSER(fileChooser)));
|
||||
directory = directory + "/..";
|
||||
#elif defined TARGET_OS_Windows
|
||||
directory = "..";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef TARGET_OS_Linux
|
||||
if(needFilePrefix) directory = "file://" + directory;
|
||||
gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(fileChooser), directory.c_str());
|
||||
#elif defined TARGET_OS_Windows
|
||||
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fileChooser), directory.c_str());
|
||||
#endif
|
||||
|
||||
getLogManager() << Kernel::LogLevel_Info << "Driver entries from [" << filename << "] loaded.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDriverSkeletonGenerator::getCurrentParameters()
|
||||
{
|
||||
GtkWidget* driverName = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_driver_name"));
|
||||
m_DriverName = gtk_entry_get_text(GTK_ENTRY(driverName));
|
||||
GtkWidget* className = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_class_name"));
|
||||
m_ClassName = gtk_entry_get_text(GTK_ENTRY(className));
|
||||
GtkWidget* minChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_min_channel"));
|
||||
m_MinChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(minChannel))));
|
||||
GtkWidget* maxChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_max_channel"));
|
||||
m_MaxChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(maxChannel))));
|
||||
GtkWidget* sf = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_sampling_frequencies"));
|
||||
m_Samplings = gtk_entry_get_text(GTK_ENTRY(sf));
|
||||
GtkWidget* fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
|
||||
char* directory = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fileChooser));
|
||||
m_directory = CString(directory);
|
||||
g_free(directory);
|
||||
}
|
||||
|
||||
} // namespace SkeletonGenerator
|
||||
} // namespace OpenViBE
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovsgCSkeletonGenerator.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace SkeletonGenerator {
|
||||
class CDriverSkeletonGenerator final : public CSkeletonGenerator
|
||||
{
|
||||
public:
|
||||
|
||||
CDriverSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder) : CSkeletonGenerator(ctx, builder) { }
|
||||
~CDriverSkeletonGenerator() override { }
|
||||
|
||||
bool initialize() override;
|
||||
bool save(const std::string& filename) override;
|
||||
bool load(const std::string& filename) override;
|
||||
void getCurrentParameters() override;
|
||||
|
||||
std::string m_DriverName;
|
||||
std::string m_ClassName;
|
||||
std::string m_Samplings;
|
||||
std::vector<std::string> m_SamplingSeparate;
|
||||
std::string m_MinChannel;
|
||||
std::string m_MaxChannel;
|
||||
|
||||
void buttonCheckCB();
|
||||
void buttonOkCB();
|
||||
void buttonTooltipCB(GtkButton* button);
|
||||
void buttonExitCB();
|
||||
|
||||
private:
|
||||
|
||||
Kernel::ILogManager& getLogManager() const override { return m_kernelCtx.getLogManager(); }
|
||||
Kernel::IErrorManager& getErrorManager() const override { return m_kernelCtx.getErrorManager(); }
|
||||
|
||||
enum class EWidgetName
|
||||
{
|
||||
DriverName,
|
||||
ClassName,
|
||||
ChannelCount,
|
||||
Sampling,
|
||||
Directory,
|
||||
};
|
||||
|
||||
std::map<GtkButton*, EWidgetName> m_widgetNames;
|
||||
};
|
||||
} // namespace SkeletonGenerator
|
||||
} // namespace OpenViBE
|
||||
+249
@@ -0,0 +1,249 @@
|
||||
#include "ovsgCSkeletonGenerator.h"
|
||||
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace SkeletonGenerator {
|
||||
|
||||
CSkeletonGenerator::CSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder)
|
||||
: m_kernelCtx(ctx), m_builder(builder)
|
||||
{
|
||||
m_configFile = m_kernelCtx.getConfigurationManager().expand("${CustomConfigurationApplication}");
|
||||
m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "Configuration file [" << m_configFile << "]\n";
|
||||
loadCommonParameters(m_configFile);
|
||||
}
|
||||
|
||||
void CSkeletonGenerator::getCommonParameters()
|
||||
{
|
||||
//Author and Company
|
||||
GtkWidget* company = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_company_name"));
|
||||
m_company = gtk_entry_get_text(GTK_ENTRY(company));
|
||||
|
||||
GtkWidget* author = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_author_name"));
|
||||
m_author = gtk_entry_get_text(GTK_ENTRY(author));
|
||||
}
|
||||
|
||||
bool CSkeletonGenerator::saveCommonParameters(const std::string& filename)
|
||||
{
|
||||
// we get the latest values
|
||||
getCommonParameters();
|
||||
|
||||
std::ofstream file;
|
||||
file.open(filename, std::ios::app | std::ios::binary);
|
||||
OV_ERROR_UNLESS_KRF(file.is_open(), "Saving the common entries in [" << filename << "] failed !", Kernel::ErrorType::BadFileRead);
|
||||
|
||||
|
||||
// generator selected
|
||||
std::string active;
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-selection-radio-button")))) { active = "0"; }
|
||||
else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_builder, "sg-algo-selection-radio-button")))) { active = "1"; }
|
||||
else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_builder, "sg-box-selection-radio-button")))) { active = "2"; }
|
||||
|
||||
file << "SkeletonGenerator_GeneratorSelected = " << active << std::endl;
|
||||
file << "SkeletonGenerator_Common_Author = " << m_author << std::endl;
|
||||
file << "SkeletonGenerator_Common_Company = " << m_company << std::endl;
|
||||
file.close();
|
||||
getLogManager() << Kernel::LogLevel_Info << "Common entries saved in [" << filename << "]\n";
|
||||
|
||||
//we can reload the file, it may have changed
|
||||
m_configFileLoaded = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSkeletonGenerator::cleanConfigurationFile(const std::string& filename) const
|
||||
{
|
||||
std::ofstream file;
|
||||
file.open(filename, std::ios::binary);
|
||||
OV_ERROR_UNLESS_KRF(file.is_open(), "Failed to clean [" << filename << "]", Kernel::ErrorType::BadFileRead);
|
||||
|
||||
getLogManager() << Kernel::LogLevel_Info << "Configuration file [" << filename << "] cleaned.\n";
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSkeletonGenerator::loadCommonParameters(const std::string& filename)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_configFileLoaded || m_kernelCtx.getConfigurationManager().addConfigurationFromFile(filename.c_str()),
|
||||
"Common: Configuration file [" << filename << "] could not be loaded. \n", Kernel::ErrorType::BadFileRead);
|
||||
|
||||
GtkWidget* widget = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-selection-radio-button"));
|
||||
gtk_toggle_button_set_active(
|
||||
GTK_TOGGLE_BUTTON(widget), (m_kernelCtx.getConfigurationManager().expandAsUInteger("${SkeletonGenerator_GeneratorSelected}") == 0));
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-algo-selection-radio-button"));
|
||||
gtk_toggle_button_set_active(
|
||||
GTK_TOGGLE_BUTTON(widget), (m_kernelCtx.getConfigurationManager().expandAsUInteger("${SkeletonGenerator_GeneratorSelected}") == 1));
|
||||
widget = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-box-selection-radio-button"));
|
||||
gtk_toggle_button_set_active(
|
||||
GTK_TOGGLE_BUTTON(widget), (m_kernelCtx.getConfigurationManager().expandAsUInteger("${SkeletonGenerator_GeneratorSelected}") == 2));
|
||||
|
||||
GtkWidget* company = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_company_name"));
|
||||
gtk_entry_set_text(GTK_ENTRY(company), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Common_Company}"));
|
||||
|
||||
GtkWidget* author = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_author_name"));
|
||||
gtk_entry_set_text(GTK_ENTRY(author), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Common_Author}"));
|
||||
|
||||
getLogManager() << Kernel::LogLevel_Info << "Common entries from [" << filename << "] loaded.\n";
|
||||
|
||||
m_configFileLoaded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CSkeletonGenerator::ensureSedCompliancy(const std::string& expression)
|
||||
{
|
||||
std::string res(expression);
|
||||
auto it = res.begin();
|
||||
while (it < res.end())
|
||||
{
|
||||
if ((*it) == '\\')
|
||||
{
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
#ifdef TARGET_OS_Linux
|
||||
it = res.insert(it,'\\');
|
||||
it = res.insert(it,'\\');
|
||||
it+=2;
|
||||
it = res.insert(it,'\\');
|
||||
it = res.insert(it,'\\');
|
||||
it+=2;
|
||||
#endif
|
||||
}
|
||||
else if ((*it) == '/')
|
||||
{
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
}
|
||||
else if ((*it) == '"')
|
||||
{
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
it = res.insert(it, '\\');
|
||||
++it;
|
||||
}
|
||||
else if ((*it) == '\n')
|
||||
{
|
||||
it = res.erase(it);
|
||||
#ifdef TARGET_OS_Linux
|
||||
it = res.insert(it,'\\');
|
||||
it = res.insert(it,'\\');
|
||||
it+=2;
|
||||
#endif
|
||||
it = res.insert(it, '\\');
|
||||
it = res.insert(it, '\\');
|
||||
it += 2;
|
||||
it = res.insert(it, 'n');
|
||||
//++it;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CSkeletonGenerator::regexReplace(const std::string& src, const std::string& regEx, const std::string& substitute, const std::string& dst) const
|
||||
{
|
||||
try
|
||||
{
|
||||
// Read file to memory
|
||||
std::ifstream in(src);
|
||||
std::string buffer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
|
||||
in.close();
|
||||
|
||||
// Open output stream and set an iterator to it
|
||||
std::string realDst((dst.empty() ? src : dst));
|
||||
std::ofstream out(realDst);
|
||||
const std::ostream_iterator<char> it(out);
|
||||
|
||||
// Do regex magic on the iterator
|
||||
boost::regex exp;
|
||||
exp.assign(regEx);
|
||||
|
||||
regex_replace(it, buffer.begin(), buffer.end(), exp, substitute, boost::match_default | boost::format_sed);
|
||||
|
||||
out.close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "Error occurred processing " << src << " to " << dst << "\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CSkeletonGenerator::getDate()
|
||||
{
|
||||
time_t raw;
|
||||
time(&raw);
|
||||
struct tm* info = localtime(&raw);
|
||||
std::string res(asctime(info));
|
||||
res = res.substr(0, res.size() - 1); // the ascitime ends with a "\n"
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CSkeletonGenerator::generate(const std::string& src, const std::string& dst, const std::map<std::string, std::string>& substitutions,
|
||||
std::string& log) const
|
||||
{
|
||||
// we check if the template file is in place.
|
||||
if (! g_file_test(src.c_str(), G_FILE_TEST_EXISTS))
|
||||
{
|
||||
log += "[FAILED] the template file '" + src + "' is missing.\n";
|
||||
OV_ERROR_KRF("The template file '" << src << "' is missing.", Kernel::ErrorType::BadInput);
|
||||
}
|
||||
|
||||
// we check the map
|
||||
if (substitutions.empty())
|
||||
{
|
||||
log += "[WARNING] No substitution provided.\n";
|
||||
OV_WARNING_K("No substitution provided.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
log += "[ OK ] -- template file '" + src + "' found.\n";
|
||||
getLogManager() << Kernel::LogLevel_Info << " -- template file '" << src << "' found.\n";
|
||||
|
||||
//we need to create the destination file by copying the template file, then do the first substitution
|
||||
auto it = substitutions.cbegin();
|
||||
success &= regexReplace(src, it->first, ensureSedCompliancy(it->second), dst);
|
||||
++it;
|
||||
|
||||
//next substitutions are done on the - incomplete - destination file itself
|
||||
while (it != substitutions.cend() && success)
|
||||
{
|
||||
getLogManager() << Kernel::LogLevel_Trace << "Executing substitution [" << it->first << "] ->[" << it->second << "]\n";
|
||||
success &= regexReplace(dst, it->first, ensureSedCompliancy(it->second));
|
||||
++it;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
log += "[FAILED] -- " + dst + " cannot be written.\n";
|
||||
OV_ERROR_KRF(" -- " << dst << " cannot be written.", Kernel::ErrorType::BadFileWrite);
|
||||
}
|
||||
|
||||
log += "[ OK ] -- " + dst + " written.\n";
|
||||
getLogManager() << Kernel::LogLevel_Info << " -- " << dst << " written.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace SkeletonGenerator
|
||||
} // namespace OpenViBE
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
#include <openvibe/kernel/ovIKernelObject.h>
|
||||
//#include <configuration/ovkCConfigurationManager.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace SkeletonGenerator {
|
||||
class CSkeletonGenerator
|
||||
{
|
||||
public:
|
||||
|
||||
CSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder);
|
||||
virtual ~CSkeletonGenerator() { }
|
||||
|
||||
protected:
|
||||
Kernel::IKernelContext& m_kernelCtx;
|
||||
|
||||
GtkBuilder* m_builder = nullptr;
|
||||
|
||||
std::string m_author;
|
||||
std::string m_company;
|
||||
std::string m_directory;
|
||||
std::string m_configFile; // basic application config file
|
||||
bool m_configFileLoaded = false;
|
||||
|
||||
virtual bool initialize() = 0;
|
||||
|
||||
void getCommonParameters();
|
||||
bool saveCommonParameters(const std::string& filename);
|
||||
bool loadCommonParameters(const std::string& filename);
|
||||
|
||||
bool cleanConfigurationFile(const std::string& filename) const;
|
||||
|
||||
// returns a sed-compliant expression to be parsed in a substitution command
|
||||
static std::string ensureSedCompliancy(const std::string& expression);
|
||||
// executes a regex replace and builds a new file, by replacing the matching expressions by the substitute. If no destination file is provided, the template file is modified.
|
||||
// Note that the input must be a valid sed format regex pattern, the function does not check.
|
||||
bool regexReplace(const std::string& src, const std::string& regEx, const std::string& substitute, const std::string& dst = std::string("")) const;
|
||||
|
||||
// get the formatted string date
|
||||
static std::string getDate();
|
||||
|
||||
// generate a new file, giving a template file, a destination file, and a map ofsubstitutions (Tag,Substitute)
|
||||
// return false if an error occurred.
|
||||
bool generate(const std::string& src, const std::string& dst, const std::map<std::string, std::string>& substitutions, std::string& log) const;
|
||||
|
||||
virtual void getCurrentParameters() = 0;
|
||||
virtual bool save(const std::string& filename) = 0;
|
||||
virtual bool load(const std::string& filename) = 0;
|
||||
|
||||
virtual Kernel::ILogManager& getLogManager() const { return m_kernelCtx.getLogManager(); }
|
||||
virtual Kernel::IErrorManager& getErrorManager() const { return m_kernelCtx.getErrorManager(); }
|
||||
};
|
||||
} // namespace SkeletonGenerator
|
||||
} // namespace OpenViBE
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <clocale> // std::setlocale
|
||||
|
||||
#include "ovsgCDriverSkeletonGenerator.h"
|
||||
#include "ovsgCBoxAlgorithmSkeletonGenerator.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
OpenViBE::CKernelLoader loader;
|
||||
|
||||
std::cout << "[ INF ] Created kernel loader, trying to load kernel module" << std::endl;
|
||||
OpenViBE::CString err;
|
||||
#if defined TARGET_OS_Windows
|
||||
const OpenViBE::CString file = OpenViBE::Directories::getLibDir() + "/openvibe-kernel.dll";
|
||||
#else
|
||||
const OpenViBE::CString file = OpenViBE::Directories::getLibDir() + "/libopenvibe-kernel.so";
|
||||
#endif
|
||||
if (!loader.load(file, &err)) { std::cout << "[ FAILED ] Error loading kernel (" << err << ")" << " from [" << file << "]\n"; }
|
||||
else
|
||||
{
|
||||
std::cout << "[ INF ] Kernel module loaded, trying to get kernel descriptor" << std::endl;
|
||||
OpenViBE::Kernel::IKernelDesc* desc = nullptr;
|
||||
loader.initialize();
|
||||
loader.getKernelDesc(desc);
|
||||
if (!desc) { std::cout << "[ FAILED ] No kernel descriptor" << std::endl; }
|
||||
else
|
||||
{
|
||||
std::cout << "[ INF ] Got kernel descriptor, trying to create kernel" << std::endl;
|
||||
OpenViBE::Kernel::IKernelContext* ctx = desc->createKernel("skeleton-generator", OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
|
||||
if (!ctx || !ctx->initialize()) { std::cout << "[ FAILED ] No kernel created by kernel descriptor" << std::endl; }
|
||||
else
|
||||
{
|
||||
ctx->getConfigurationManager().addConfigurationFromFile(OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
|
||||
ctx->getConfigurationManager().addConfigurationFromFile(
|
||||
OpenViBE::Directories::getDataDir() + "/applications/skeleton-generator/skeleton-generator.conf");
|
||||
OpenViBE::Toolkit::initialize(*ctx);
|
||||
OpenViBE::Kernel::IConfigurationManager& configMgr = ctx->getConfigurationManager();
|
||||
ctx->getPluginManager().addPluginsFromFiles(configMgr.expand("${Kernel_Plugins}"));
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
// We rely on this with 64bit/gtk 2.24, to roll back gtk_init() sometimes switching
|
||||
// the locale to one where ',' is needed instead of '.' for separators of floats,
|
||||
// causing issues, for example getConfigurationManager.expandAsFloat("0.05") -> 0;
|
||||
// due to implementation by std::stod().
|
||||
std::setlocale(LC_ALL, "C");
|
||||
|
||||
GtkBuilder* builder = gtk_builder_new();
|
||||
const OpenViBE::CString filename = OpenViBE::Directories::getDataDir() + "/applications/skeleton-generator/generator-interface.ui";
|
||||
|
||||
OV_ERROR_UNLESS(gtk_builder_add_from_file(builder, filename.toASCIIString(), nullptr), "Problem loading [" << filename << "]",
|
||||
OpenViBE::Kernel::ErrorType::BadFileRead, -1, ctx->getErrorManager(), ctx->getLogManager());
|
||||
|
||||
//gtk_builder_connect_signals(builder, nullptr);
|
||||
|
||||
GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "sg-selection-dialog"));
|
||||
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
|
||||
|
||||
GtkWidget* radioDriver = GTK_WIDGET(gtk_builder_get_object(builder, "sg-driver-selection-radio-button"));
|
||||
GtkWidget* radioAlgo = GTK_WIDGET(gtk_builder_get_object(builder, "sg-algo-selection-radio-button"));
|
||||
GtkWidget* radioBox = GTK_WIDGET(gtk_builder_get_object(builder, "sg-box-selection-radio-button"));
|
||||
|
||||
|
||||
OpenViBE::SkeletonGenerator::CBoxAlgorithmSkeletonGenerator boxGenerator(*ctx, builder);
|
||||
OpenViBE::SkeletonGenerator::CDriverSkeletonGenerator driverGenerator(*ctx, builder);
|
||||
|
||||
const gint resp = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
if (resp == GTK_RESPONSE_OK)
|
||||
{
|
||||
gtk_widget_hide(GTK_WIDGET(dialog));
|
||||
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioDriver))) { driverGenerator.initialize(); }
|
||||
OV_ERROR_UNLESS(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioAlgo)), "NOT YET AVAILABLE.",
|
||||
OpenViBE::Kernel::ErrorType::Internal, 0, ctx->getErrorManager(), ctx->getLogManager());
|
||||
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioBox))) { boxGenerator.initialize(); }
|
||||
gtk_main();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "User cancelled. Exit." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loader.uninitialize();
|
||||
loader.unload();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user