|
|
|
|
|
|
|
|
#include "ovpCBoxAlgorithmP300TactileVisualization.h"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace OpenViBE;
|
|
|
|
|
|
using namespace /*OpenViBE::*/Kernel;
|
|
|
|
|
|
using namespace /*OpenViBE::*/Plugins;
|
|
|
|
|
|
using namespace /*OpenViBE::Plugins::*/Tactilebci;
|
|
|
|
|
|
|
|
|
|
|
|
// This callback flushes all accumulated stimulations to the TCP Tagging
|
|
|
|
|
|
// after the rendering has completed.
|
|
|
|
|
|
static gboolean FlushCB(gpointer data)
|
|
|
|
|
|
{
|
|
|
|
|
|
(static_cast<CBoxAlgorithmP300TactileVisualization*>(data))->flushQueue();
|
|
|
|
|
|
|
|
|
|
|
|
return false; // Only run once
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::initialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
// ------ Init decoder/encoder
|
|
|
|
|
|
m_SequenceInputDecoder.initialize(*this, 0);
|
|
|
|
|
|
m_TargetInputDecoder.initialize(*this, 1);
|
|
|
|
|
|
m_ResultInputDecoder.initialize(*this, 2);
|
|
|
|
|
|
m_ResultOutputEncoder.initialize(*this, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Get box settings
|
|
|
|
|
|
m_InterfaceFilename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
|
|
|
|
|
m_RowBase = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
|
|
|
|
|
|
m_nTactilos = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
|
|
|
|
|
|
m_FreeSpelling = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3);
|
|
|
|
|
|
|
|
|
|
|
|
//set m_nTactilos minimum number of 2, if lower
|
|
|
|
|
|
if(m_nTactilos < 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_nTactilos = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//set m_nTactilos maximum number of MAX_TACTILOS(10), if higher
|
|
|
|
|
|
if(m_nTactilos > MAX_TACTILOS)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_nTactilos = MAX_TACTILOS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Setup acquisition server TCP tagging
|
|
|
|
|
|
m_stimuliQueue.clear();
|
|
|
|
|
|
m_stimulusSender = TCPTagging::CreateStimulusSender();
|
|
|
|
|
|
if(!m_stimulusSender->connect("localhost", "15361"))
|
|
|
|
|
|
{
|
|
|
|
|
|
this->getLogManager() << LogLevel_Warning << "Failed to connect to acquisition server TCP tagging.\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Gtk variables
|
|
|
|
|
|
// Build main UI elements
|
|
|
|
|
|
m_MainWidgetInterface = gtk_builder_new();
|
|
|
|
|
|
if(!gtk_builder_add_from_file(m_MainWidgetInterface, m_InterfaceFilename.toASCIIString(), nullptr))//error
|
|
|
|
|
|
{
|
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "Failed to load UI file [" << m_InterfaceFilename << "]\n";
|
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "Make sure, that the given filename and path are correct\n";
|
|
|
|
|
|
return(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_MainWindow = GTK_WIDGET(gtk_builder_get_object(m_MainWidgetInterface, "p300-tactile-main"));
|
|
|
|
|
|
m_Table = GTK_TABLE(gtk_builder_get_object(m_MainWidgetInterface, "p300-tactile-table"));
|
|
|
|
|
|
m_ResultLabel = GTK_LABEL(gtk_builder_get_object(m_MainWidgetInterface, "label-result"));
|
|
|
|
|
|
m_TargetLabel = GTK_LABEL(gtk_builder_get_object(m_MainWidgetInterface, "label-target"));
|
|
|
|
|
|
|
|
|
|
|
|
// Create font description
|
|
|
|
|
|
m_FontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_MainWindow)));
|
|
|
|
|
|
pango_font_description_set_size(m_FontDesc, gint(FontSize*PANGO_SCALE));
|
|
|
|
|
|
|
|
|
|
|
|
// test if the UI-file fits the number of tactilos
|
|
|
|
|
|
guint nRow = 0;
|
|
|
|
|
|
g_object_get(m_Table, "n-rows", &nRow, nullptr);
|
|
|
|
|
|
if(m_nTactilos != nRow)
|
|
|
|
|
|
{
|
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "The number of tactilos " << m_nTactilos<<" used and the number of rows "<< nRow << " in the ui file must be the same.\n";
|
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "Make sure to choose the right UI-File, e.g. p300-tactile-6.ui for 6 tactilos\n";
|
|
|
|
|
|
return(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string eventbox_id = "eventbox-" + std::to_string(i+1);
|
|
|
|
|
|
|
|
|
|
|
|
m_EventBox.push_back(GTK_WIDGET(gtk_builder_get_object(m_MainWidgetInterface, eventbox_id.c_str())));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Setup tactile UI
|
|
|
|
|
|
//Create UI for m_nTactilos = 6
|
|
|
|
|
|
if(m_nTactilos == 6)
|
|
|
|
|
|
{
|
|
|
|
|
|
//create free spelling UI for 6 tactilos
|
|
|
|
|
|
if(m_FreeSpelling)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_Menu.push_back(TactileMenu(6));
|
|
|
|
|
|
m_Menu[0].set_LabelText(0, "Ja");
|
|
|
|
|
|
m_Menu[0].set_LabelText(1, "Nein");
|
|
|
|
|
|
m_Menu[0].set_LabelText(2, "Pflege");
|
|
|
|
|
|
m_Menu[0].set_LabelText(3, "Hilfe");
|
|
|
|
|
|
m_Menu[0].set_LabelText(4, "Geräte");
|
|
|
|
|
|
m_Menu[0].set_LabelText(5, "Funktionen");
|
|
|
|
|
|
|
|
|
|
|
|
m_Menu.push_back(TactileMenu(6));
|
|
|
|
|
|
m_Menu[1].set_LabelText(0, "Ja");
|
|
|
|
|
|
m_Menu[1].set_LabelText(1, "Nein");
|
|
|
|
|
|
m_Menu[1].set_LabelText(2, "Hunger");
|
|
|
|
|
|
m_Menu[1].set_LabelText(3, "Lage");
|
|
|
|
|
|
m_Menu[1].set_LabelText(4, "Müdigkeit");
|
|
|
|
|
|
m_Menu[1].set_LabelText(5, "Hauptmenü");
|
|
|
|
|
|
|
|
|
|
|
|
m_Menu.push_back(TactileMenu(6));
|
|
|
|
|
|
m_Menu[2].set_LabelText(0, "Ja");
|
|
|
|
|
|
m_Menu[2].set_LabelText(1, "Nein");
|
|
|
|
|
|
m_Menu[2].set_LabelText(2, "Schmerzen");
|
|
|
|
|
|
m_Menu[2].set_LabelText(3, "Atemnot");
|
|
|
|
|
|
m_Menu[2].set_LabelText(4, "Anderes");
|
|
|
|
|
|
m_Menu[2].set_LabelText(5, "Hauptmenü");
|
|
|
|
|
|
|
|
|
|
|
|
m_Menu.push_back(TactileMenu(6));
|
|
|
|
|
|
m_Menu[3].set_LabelText(0, "Ja");
|
|
|
|
|
|
m_Menu[3].set_LabelText(1, "Nein");
|
|
|
|
|
|
m_Menu[3].set_LabelText(2, "Atemgerät");
|
|
|
|
|
|
m_Menu[3].set_LabelText(3, "Rollstuhl");
|
|
|
|
|
|
m_Menu[3].set_LabelText(4, "Computer");
|
|
|
|
|
|
m_Menu[3].set_LabelText(5, "Hauptmenü");
|
|
|
|
|
|
|
|
|
|
|
|
//set SubMenu ptr
|
|
|
|
|
|
m_Menu[0].set_SubMenu(2, &m_Menu[1]);
|
|
|
|
|
|
m_Menu[0].set_SubMenu(3, &m_Menu[2]);
|
|
|
|
|
|
m_Menu[0].set_SubMenu(4, &m_Menu[3]);
|
|
|
|
|
|
m_Menu[1].set_SubMenu(5, &m_Menu[0]);
|
|
|
|
|
|
m_Menu[2].set_SubMenu(5, &m_Menu[0]);
|
|
|
|
|
|
m_Menu[3].set_SubMenu(5, &m_Menu[0]);
|
|
|
|
|
|
|
|
|
|
|
|
//set curr Menu ptr to main menu
|
|
|
|
|
|
m_CurrMenu = &m_Menu[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
//create copy spelling UI for 6 tactilos
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
m_Menu.push_back(TactileMenu(6));
|
|
|
|
|
|
m_Menu[0].set_LabelText(0, "Hand links");
|
|
|
|
|
|
m_Menu[0].set_LabelText(1, "Arm links");
|
|
|
|
|
|
m_Menu[0].set_LabelText(2, "Brust links");
|
|
|
|
|
|
m_Menu[0].set_LabelText(3, "Brust rechts");
|
|
|
|
|
|
m_Menu[0].set_LabelText(4, "Arm rechts");
|
|
|
|
|
|
m_Menu[0].set_LabelText(5, "Hand rechts");
|
|
|
|
|
|
|
|
|
|
|
|
m_CurrMenu = &m_Menu[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//Create default UI for m_nTactilos != 6
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
m_Menu.push_back(TactileMenu(m_nTactilos));
|
|
|
|
|
|
m_CurrMenu = &m_Menu[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Init UI
|
|
|
|
|
|
m_visualizationCtx = dynamic_cast<VisualizationToolkit::IVisualizationContext*>(this->createPluginObject(OVP_ClassId_Plugin_VisualizationCtx));
|
|
|
|
|
|
m_visualizationCtx->setWidget(*this, m_MainWindow);
|
|
|
|
|
|
|
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
resetColor();
|
|
|
|
|
|
gtk_widget_modify_font(gtk_bin_get_child(GTK_BIN(m_EventBox[i])), m_FontDesc);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
toggleLabelText();
|
|
|
|
|
|
|
|
|
|
|
|
return(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::uninitialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
// ------ uninitialize decoder/encoder
|
|
|
|
|
|
m_SequenceInputDecoder.uninitialize();
|
|
|
|
|
|
m_TargetInputDecoder.uninitialize();
|
|
|
|
|
|
m_ResultInputDecoder.uninitialize();
|
|
|
|
|
|
m_ResultOutputEncoder.uninitialize();
|
|
|
|
|
|
|
|
|
|
|
|
// ------ uninitialize GTK UI
|
|
|
|
|
|
if (m_MainWidgetInterface)
|
|
|
|
|
|
{
|
|
|
|
|
|
g_object_unref(m_MainWidgetInterface);
|
|
|
|
|
|
m_MainWidgetInterface = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (m_visualizationCtx)
|
|
|
|
|
|
{
|
|
|
|
|
|
this->releasePluginObject(m_visualizationCtx);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ uinitialize TCP Tagging
|
|
|
|
|
|
if (m_idleFuncTag != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_stimuliQueue.clear();
|
|
|
|
|
|
g_source_remove(m_idleFuncTag);
|
|
|
|
|
|
m_idleFuncTag = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (m_stimulusSender)
|
|
|
|
|
|
{
|
|
|
|
|
|
delete m_stimulusSender;
|
|
|
|
|
|
m_stimulusSender = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::processInput(const size_t index)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ------ ready to process
|
|
|
|
|
|
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
|
|
|
|
|
|
|
|
|
|
|
return(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::process()
|
|
|
|
|
|
{
|
|
|
|
|
|
const IBox& staticBoxContext=this->getStaticBoxContext();
|
|
|
|
|
|
IBoxIO& boxContext = this->getDynamicBoxContext();
|
|
|
|
|
|
|
|
|
|
|
|
//variables for processing of input chunks
|
|
|
|
|
|
uint64_t SequenceID = 0;
|
|
|
|
|
|
uint64_t TargetID = 0;
|
|
|
|
|
|
uint64_t ResultID = 0;
|
|
|
|
|
|
int Row = -1;
|
|
|
|
|
|
bool IsTarget = false;
|
|
|
|
|
|
bool TargetReceived = false;
|
|
|
|
|
|
bool ResultReceived = false;
|
|
|
|
|
|
|
|
|
|
|
|
//variables for forwarding of target stimulations
|
|
|
|
|
|
uint64_t ChunkStartTime = 0;
|
|
|
|
|
|
uint64_t ChunkEndTime = 0;
|
|
|
|
|
|
uint64_t Size = 0;
|
|
|
|
|
|
const uint8_t* Buffer = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Sequence stimulation
|
|
|
|
|
|
for(uint64_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_SequenceInputDecoder.decode(i);
|
|
|
|
|
|
m_LastTime = boxContext.getInputChunkEndTime(0, i);
|
|
|
|
|
|
|
|
|
|
|
|
// if header received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isHeaderReceived())
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
// if buffer received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isBufferReceived())
|
|
|
|
|
|
{
|
|
|
|
|
|
//check received stimulations on sequence input
|
|
|
|
|
|
CStimulationSet* SequenceStimulationSet = m_SequenceInputDecoder.getOutputStimulationSet();
|
|
|
|
|
|
for(uint64_t j = 0; j < SequenceStimulationSet->size(); ++j)
|
|
|
|
|
|
{
|
|
|
|
|
|
SequenceID = SequenceStimulationSet->getId(j);
|
|
|
|
|
|
|
|
|
|
|
|
if(SequenceID >= m_RowBase && SequenceID < m_RowBase + m_nTactilos)
|
|
|
|
|
|
{
|
|
|
|
|
|
Row = SequenceID - m_RowBase;
|
|
|
|
|
|
IsTarget = (Row == (int)m_LastTarget);
|
|
|
|
|
|
}
|
|
|
|
|
|
if(SequenceID == OVTK_StimulationId_VisualStimulationStart)
|
|
|
|
|
|
{
|
|
|
|
|
|
resetColor();
|
|
|
|
|
|
toggleFlashColor(Row);
|
|
|
|
|
|
if (IsTarget)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_stimuliQueue.push_back(OVTK_StimulationId_Target);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
m_stimuliQueue.push_back(OVTK_StimulationId_NonTarget);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if(SequenceID == OVTK_StimulationId_VisualStimulationStop)
|
|
|
|
|
|
{
|
|
|
|
|
|
resetColor();
|
|
|
|
|
|
}
|
|
|
|
|
|
if(SequenceID == OVTK_StimulationId_SegmentStart)
|
|
|
|
|
|
{
|
|
|
|
|
|
toggleLabelText();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_stimuliQueue.push_back(SequenceID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if end received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isEndReceived())
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
boxContext.markInputAsDeprecated(0, i);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Target stimulation
|
|
|
|
|
|
for(uint64_t i = 0; i < boxContext.getInputChunkCount(1); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(m_LastTime >= boxContext.getInputChunkStartTime(1, i))
|
|
|
|
|
|
{
|
|
|
|
|
|
m_TargetInputDecoder.decode(i);
|
|
|
|
|
|
|
|
|
|
|
|
// if header received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isHeaderReceived())
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
// if buffer received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isBufferReceived())
|
|
|
|
|
|
{
|
|
|
|
|
|
// check received dtimulations on Target input
|
|
|
|
|
|
CStimulationSet* TargetStimulationSet = m_TargetInputDecoder.getOutputStimulationSet();
|
|
|
|
|
|
for(uint64_t j = 0; j < TargetStimulationSet->size(); ++j)
|
|
|
|
|
|
{
|
|
|
|
|
|
TargetID = TargetStimulationSet->getId(j);
|
|
|
|
|
|
|
|
|
|
|
|
if(TargetID >= m_RowBase && TargetID < m_RowBase + m_nTactilos)
|
|
|
|
|
|
{
|
|
|
|
|
|
Row = TargetID - m_RowBase;
|
|
|
|
|
|
TargetReceived = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(TargetReceived)
|
|
|
|
|
|
{
|
|
|
|
|
|
toggleTargetColor(Row);
|
|
|
|
|
|
m_stimuliQueue.push_back(TargetID);
|
|
|
|
|
|
|
|
|
|
|
|
std::string TargetLabel = gtk_label_get_text(m_TargetLabel);
|
|
|
|
|
|
TargetLabel += gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[Row]))));
|
|
|
|
|
|
gtk_label_set_text(m_TargetLabel, TargetLabel.c_str());
|
|
|
|
|
|
|
|
|
|
|
|
m_LastTarget = Row;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if end received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isEndReceived())
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
boxContext.markInputAsDeprecated(1, i);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Result stimulation
|
|
|
|
|
|
for(uint64_t i = 0; i < boxContext.getInputChunkCount(2); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(m_LastTime >= boxContext.getInputChunkStartTime(2, i))
|
|
|
|
|
|
{
|
|
|
|
|
|
m_ResultInputDecoder.decode(i);
|
|
|
|
|
|
|
|
|
|
|
|
// if header received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isHeaderReceived())
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
// if buffer received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isBufferReceived())
|
|
|
|
|
|
{
|
|
|
|
|
|
// check received stimulations on result input
|
|
|
|
|
|
CStimulationSet* ResultStimulationSet = m_ResultInputDecoder.getOutputStimulationSet();
|
|
|
|
|
|
for(uint64_t j = 0; j < ResultStimulationSet->size(); ++j)
|
|
|
|
|
|
{
|
|
|
|
|
|
ResultID = ResultStimulationSet->getId(j);
|
|
|
|
|
|
|
|
|
|
|
|
if(ResultID >= m_RowBase && ResultID < m_RowBase + m_nTactilos)
|
|
|
|
|
|
{
|
|
|
|
|
|
Row = ResultID - m_RowBase;
|
|
|
|
|
|
ResultReceived = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(ResultReceived)
|
|
|
|
|
|
{
|
|
|
|
|
|
toggleResultColor(Row);
|
|
|
|
|
|
|
|
|
|
|
|
std::string ResultLabel = gtk_label_get_text(m_ResultLabel);
|
|
|
|
|
|
ResultLabel += gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[Row]))));
|
|
|
|
|
|
gtk_label_set_text(m_ResultLabel, ResultLabel.c_str());
|
|
|
|
|
|
|
|
|
|
|
|
//switch current menu ptr to submenu
|
|
|
|
|
|
if(m_CurrMenu->get_SubMenu(Row) != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_CurrMenu = m_CurrMenu->get_SubMenu(Row);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if end received
|
|
|
|
|
|
if(m_SequenceInputDecoder.isEndReceived())
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
// forward target stimulations
|
|
|
|
|
|
boxContext.getInputChunk(2, i, ChunkStartTime, ChunkEndTime, Size, Buffer);
|
|
|
|
|
|
boxContext.appendOutputChunkData(0, Buffer, Size);
|
|
|
|
|
|
boxContext.markOutputAsReadyToSend(0, ChunkStartTime, ChunkEndTime);
|
|
|
|
|
|
boxContext.markInputAsDeprecated(2, i);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Send accumulated stimuli to the acquisition server
|
|
|
|
|
|
if(m_idleFuncTag == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_idleFuncTag = g_idle_add(FlushCB, this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Function Definitions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sends all accumulated stimuli to the TCP Tagging
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::flushQueue()
|
|
|
|
|
|
{
|
|
|
|
|
|
for (const auto& stimulation : m_stimuliQueue)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_stimulusSender->sendStimulation(stimulation);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_stimuliQueue.clear();
|
|
|
|
|
|
|
|
|
|
|
|
// This function will be automatically removed after completion, so set to 0
|
|
|
|
|
|
m_idleFuncTag = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Change labels fore-/background
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleFlashColor(uint64_t id)
|
|
|
|
|
|
{
|
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_FlashFG);
|
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_FlashBG);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleTargetColor(uint64_t id)
|
|
|
|
|
|
{
|
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_TargetFG);
|
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_TargetBG);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleResultColor(uint64_t id)
|
|
|
|
|
|
{
|
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_ResultFG);
|
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_ResultBG);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::resetColor()
|
|
|
|
|
|
{
|
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[i])), GTK_STATE_NORMAL, &m_NoFlashFG);
|
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[i], GTK_STATE_NORMAL, &m_NoFlashBG);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Change label text
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleLabelText()
|
|
|
|
|
|
{
|
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string label_text = m_CurrMenu->get_LabelText(i);
|
|
|
|
|
|
|
|
|
|
|
|
gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[i]))), label_text.c_str());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
#include "ovpCBoxAlgorithmP300TactileVisualization.h" |
|
|
|
|
|
|
|
|
|
|
|
using namespace OpenViBE; |
|
|
|
|
|
using namespace /*OpenViBE::*/Kernel; |
|
|
|
|
|
using namespace /*OpenViBE::*/Plugins; |
|
|
|
|
|
using namespace /*OpenViBE::Plugins::*/Tactilebci; |
|
|
|
|
|
|
|
|
|
|
|
// This callback flushes all accumulated stimulations to the TCP Tagging |
|
|
|
|
|
// after the rendering has completed. |
|
|
|
|
|
static gboolean FlushCB(gpointer data) |
|
|
|
|
|
{ |
|
|
|
|
|
(static_cast<CBoxAlgorithmP300TactileVisualization*>(data))->flushQueue(); |
|
|
|
|
|
|
|
|
|
|
|
return false; // Only run once |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::initialize() |
|
|
|
|
|
{ |
|
|
|
|
|
// ------ Init decoder/encoder |
|
|
|
|
|
m_SequenceInputDecoder.initialize(*this, 0); |
|
|
|
|
|
m_TargetInputDecoder.initialize(*this, 1); |
|
|
|
|
|
m_ResultInputDecoder.initialize(*this, 2); |
|
|
|
|
|
m_ResultOutputEncoder.initialize(*this, 0); |
|
|
|
|
|
|
|
|
|
|
|
// ------ Get box settings |
|
|
|
|
|
m_InterfaceFilename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0); |
|
|
|
|
|
m_RowBase = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1); |
|
|
|
|
|
m_nTactilos = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2); |
|
|
|
|
|
m_FreeSpelling = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3); |
|
|
|
|
|
|
|
|
|
|
|
//set m_nTactilos minimum number of 2, if lower |
|
|
|
|
|
if(m_nTactilos < 2) |
|
|
|
|
|
{ |
|
|
|
|
|
m_nTactilos = 2; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//set m_nTactilos maximum number of MAX_TACTILOS(10), if higher |
|
|
|
|
|
if(m_nTactilos > MAX_TACTILOS) |
|
|
|
|
|
{ |
|
|
|
|
|
m_nTactilos = MAX_TACTILOS; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ Setup acquisition server TCP tagging |
|
|
|
|
|
m_stimuliQueue.clear(); |
|
|
|
|
|
m_stimulusSender = TCPTagging::CreateStimulusSender(); |
|
|
|
|
|
if(!m_stimulusSender->connect("localhost", "15361")) |
|
|
|
|
|
{ |
|
|
|
|
|
this->getLogManager() << LogLevel_Warning << "Failed to connect to acquisition server TCP tagging.\n"; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ Gtk variables |
|
|
|
|
|
// Build main UI elements |
|
|
|
|
|
m_MainWidgetInterface = gtk_builder_new(); |
|
|
|
|
|
if(!gtk_builder_add_from_file(m_MainWidgetInterface, m_InterfaceFilename.toASCIIString(), nullptr))//error |
|
|
|
|
|
{ |
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "Failed to load UI file [" << m_InterfaceFilename << "]\n"; |
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "Make sure, that the given filename and path are correct\n"; |
|
|
|
|
|
return(false); |
|
|
|
|
|
} |
|
|
|
|
|
m_MainWindow = GTK_WIDGET(gtk_builder_get_object(m_MainWidgetInterface, "p300-tactile-main")); |
|
|
|
|
|
m_Table = GTK_TABLE(gtk_builder_get_object(m_MainWidgetInterface, "p300-tactile-table")); |
|
|
|
|
|
m_ResultLabel = GTK_LABEL(gtk_builder_get_object(m_MainWidgetInterface, "label-result")); |
|
|
|
|
|
m_TargetLabel = GTK_LABEL(gtk_builder_get_object(m_MainWidgetInterface, "label-target")); |
|
|
|
|
|
|
|
|
|
|
|
// Create font description |
|
|
|
|
|
m_FontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_MainWindow))); |
|
|
|
|
|
pango_font_description_set_size(m_FontDesc, gint(FontSize*PANGO_SCALE)); |
|
|
|
|
|
|
|
|
|
|
|
// test if the UI-file fits the number of tactilos |
|
|
|
|
|
guint nRow = 0; |
|
|
|
|
|
g_object_get(m_Table, "n-rows", &nRow, nullptr); |
|
|
|
|
|
if(m_nTactilos != nRow) |
|
|
|
|
|
{ |
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "The number of tactilos " << m_nTactilos<<" used and the number of rows "<< nRow << " in the ui file must be the same.\n"; |
|
|
|
|
|
this->getLogManager() << LogLevel_ImportantWarning << "Make sure to choose the right UI-File, e.g. p300-tactile-6.ui for 6 tactilos\n"; |
|
|
|
|
|
return(false); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
std::string eventbox_id = "eventbox-" + std::to_string(i+1); |
|
|
|
|
|
|
|
|
|
|
|
m_EventBox.push_back(GTK_WIDGET(gtk_builder_get_object(m_MainWidgetInterface, eventbox_id.c_str()))); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ Setup tactile UI |
|
|
|
|
|
//Create UI for m_nTactilos = 6 |
|
|
|
|
|
if(m_nTactilos == 6) |
|
|
|
|
|
{ |
|
|
|
|
|
//create free spelling UI for 6 tactilos |
|
|
|
|
|
if(m_FreeSpelling) |
|
|
|
|
|
{ |
|
|
|
|
|
//mainmenu |
|
|
|
|
|
m_Menu.push_back(TactileMenu(6)); |
|
|
|
|
|
m_Menu[0].set_LabelText(0, "Ja"); |
|
|
|
|
|
m_Menu[0].set_LabelText(1, "Nein"); |
|
|
|
|
|
m_Menu[0].set_LabelText(2, "Geräte"); |
|
|
|
|
|
m_Menu[0].set_LabelText(3, "Körper"); |
|
|
|
|
|
m_Menu[0].set_LabelText(4, "Hilfe"); |
|
|
|
|
|
m_Menu[0].set_LabelText(5, "Schmerzen"); |
|
|
|
|
|
//submenu Geräte |
|
|
|
|
|
m_Menu.push_back(TactileMenu(6)); |
|
|
|
|
|
m_Menu[1].set_LabelText(0, "Ja"); |
|
|
|
|
|
m_Menu[1].set_LabelText(1, "Nein"); |
|
|
|
|
|
m_Menu[1].set_LabelText(2, "Atemgerät"); |
|
|
|
|
|
m_Menu[1].set_LabelText(3, "Computer"); |
|
|
|
|
|
m_Menu[1].set_LabelText(4, "Rollstuhl"); |
|
|
|
|
|
m_Menu[1].set_LabelText(5, "Hauptmenü"); |
|
|
|
|
|
//submenu Körper |
|
|
|
|
|
m_Menu.push_back(TactileMenu(6)); |
|
|
|
|
|
m_Menu[2].set_LabelText(0, "Ja"); |
|
|
|
|
|
m_Menu[2].set_LabelText(1, "Nein"); |
|
|
|
|
|
m_Menu[2].set_LabelText(2, "Hunger/Durst"); |
|
|
|
|
|
m_Menu[2].set_LabelText(3, "warm/kalt"); |
|
|
|
|
|
m_Menu[2].set_LabelText(4, "Müdigkeit"); |
|
|
|
|
|
m_Menu[2].set_LabelText(5, "Hauptmenü"); |
|
|
|
|
|
//submenu Hilfe |
|
|
|
|
|
m_Menu.push_back(TactileMenu(6)); |
|
|
|
|
|
m_Menu[3].set_LabelText(0, "Ja"); |
|
|
|
|
|
m_Menu[3].set_LabelText(1, "Nein"); |
|
|
|
|
|
m_Menu[3].set_LabelText(2, "Lage"); |
|
|
|
|
|
m_Menu[3].set_LabelText(3, "Atemnot"); |
|
|
|
|
|
m_Menu[3].set_LabelText(4, "Anderes Problem"); |
|
|
|
|
|
m_Menu[3].set_LabelText(5, "Hauptmenü"); |
|
|
|
|
|
//submenu Schmerzen |
|
|
|
|
|
m_Menu.push_back(TactileMenu(6)); |
|
|
|
|
|
m_Menu[3].set_LabelText(0, "Ja"); |
|
|
|
|
|
m_Menu[3].set_LabelText(1, "Nein"); |
|
|
|
|
|
m_Menu[3].set_LabelText(2, "Kopf"); |
|
|
|
|
|
m_Menu[3].set_LabelText(3, "Torso"); |
|
|
|
|
|
m_Menu[3].set_LabelText(4, "Glieder"); |
|
|
|
|
|
m_Menu[3].set_LabelText(5, "Hauptmenü"); |
|
|
|
|
|
|
|
|
|
|
|
//set SubMenu ptr |
|
|
|
|
|
m_Menu[0].set_SubMenu(2, &m_Menu[1]);//main --> Geräte |
|
|
|
|
|
m_Menu[0].set_SubMenu(3, &m_Menu[2]);//main --> Körper |
|
|
|
|
|
m_Menu[0].set_SubMenu(4, &m_Menu[3]);//main --> Hilfe |
|
|
|
|
|
m_Menu[0].set_SubMenu(4, &m_Menu[4]);//main --> Schmerzen |
|
|
|
|
|
m_Menu[1].set_SubMenu(5, &m_Menu[0]);//Geräte --> main |
|
|
|
|
|
m_Menu[2].set_SubMenu(5, &m_Menu[0]);//Körper --> main |
|
|
|
|
|
m_Menu[3].set_SubMenu(5, &m_Menu[0]);//Hilfe --> main |
|
|
|
|
|
m_Menu[3].set_SubMenu(5, &m_Menu[0]);//Schmerzen --> main |
|
|
|
|
|
|
|
|
|
|
|
//set curr Menu ptr to main menu |
|
|
|
|
|
m_CurrMenu = &m_Menu[0]; |
|
|
|
|
|
} |
|
|
|
|
|
//create copy spelling UI for 6 tactilos |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
m_Menu.push_back(TactileMenu(6)); |
|
|
|
|
|
m_Menu[0].set_LabelText(0, "Bein links"); |
|
|
|
|
|
m_Menu[0].set_LabelText(1, "Bein rechts"); |
|
|
|
|
|
m_Menu[0].set_LabelText(2, "Arm links"); |
|
|
|
|
|
m_Menu[0].set_LabelText(3, "Arm rechts"); |
|
|
|
|
|
m_Menu[0].set_LabelText(4, "Brust"); |
|
|
|
|
|
m_Menu[0].set_LabelText(5, "Rücken"); |
|
|
|
|
|
|
|
|
|
|
|
m_CurrMenu = &m_Menu[0]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
//Create default UI for m_nTactilos != 6 |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
m_Menu.push_back(TactileMenu(m_nTactilos)); |
|
|
|
|
|
m_CurrMenu = &m_Menu[0]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ Init UI |
|
|
|
|
|
m_visualizationCtx = dynamic_cast<VisualizationToolkit::IVisualizationContext*>(this->createPluginObject(OVP_ClassId_Plugin_VisualizationCtx)); |
|
|
|
|
|
m_visualizationCtx->setWidget(*this, m_MainWindow); |
|
|
|
|
|
|
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; ++i) |
|
|
|
|
|
{ |
|
|
|
|
|
resetColor(); |
|
|
|
|
|
gtk_widget_modify_font(gtk_bin_get_child(GTK_BIN(m_EventBox[i])), m_FontDesc); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
toggleLabelText(); |
|
|
|
|
|
|
|
|
|
|
|
return(true); |
|
|
|
|
|
} |
|
|
|
|
|
/*******************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::uninitialize() |
|
|
|
|
|
{ |
|
|
|
|
|
// ------ uninitialize decoder/encoder |
|
|
|
|
|
m_SequenceInputDecoder.uninitialize(); |
|
|
|
|
|
m_TargetInputDecoder.uninitialize(); |
|
|
|
|
|
m_ResultInputDecoder.uninitialize(); |
|
|
|
|
|
m_ResultOutputEncoder.uninitialize(); |
|
|
|
|
|
|
|
|
|
|
|
// ------ uninitialize GTK UI |
|
|
|
|
|
if (m_MainWidgetInterface) |
|
|
|
|
|
{ |
|
|
|
|
|
g_object_unref(m_MainWidgetInterface); |
|
|
|
|
|
m_MainWidgetInterface = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
if (m_visualizationCtx) |
|
|
|
|
|
{ |
|
|
|
|
|
this->releasePluginObject(m_visualizationCtx); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ uinitialize TCP Tagging |
|
|
|
|
|
if (m_idleFuncTag != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
m_stimuliQueue.clear(); |
|
|
|
|
|
g_source_remove(m_idleFuncTag); |
|
|
|
|
|
m_idleFuncTag = 0; |
|
|
|
|
|
} |
|
|
|
|
|
if (m_stimulusSender) |
|
|
|
|
|
{ |
|
|
|
|
|
delete m_stimulusSender; |
|
|
|
|
|
m_stimulusSender = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return(true); |
|
|
|
|
|
} |
|
|
|
|
|
/*******************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::processInput(const size_t index) |
|
|
|
|
|
{ |
|
|
|
|
|
// ------ ready to process |
|
|
|
|
|
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess(); |
|
|
|
|
|
|
|
|
|
|
|
return(true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CBoxAlgorithmP300TactileVisualization::process() |
|
|
|
|
|
{ |
|
|
|
|
|
const IBox& staticBoxContext=this->getStaticBoxContext(); |
|
|
|
|
|
IBoxIO& boxContext = this->getDynamicBoxContext(); |
|
|
|
|
|
|
|
|
|
|
|
//variables for processing of input chunks |
|
|
|
|
|
uint64_t SequenceID = 0; |
|
|
|
|
|
uint64_t TargetID = 0; |
|
|
|
|
|
uint64_t ResultID = 0; |
|
|
|
|
|
int Row = -1; |
|
|
|
|
|
bool IsTarget = false; |
|
|
|
|
|
bool TargetReceived = false; |
|
|
|
|
|
bool ResultReceived = false; |
|
|
|
|
|
|
|
|
|
|
|
//variables for forwarding of target stimulations |
|
|
|
|
|
uint64_t ChunkStartTime = 0; |
|
|
|
|
|
uint64_t ChunkEndTime = 0; |
|
|
|
|
|
uint64_t Size = 0; |
|
|
|
|
|
const uint8_t* Buffer = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Sequence stimulation |
|
|
|
|
|
for(uint64_t i = 0; i < boxContext.getInputChunkCount(0); ++i) |
|
|
|
|
|
{ |
|
|
|
|
|
m_SequenceInputDecoder.decode(i); |
|
|
|
|
|
m_LastTime = boxContext.getInputChunkEndTime(0, i); |
|
|
|
|
|
|
|
|
|
|
|
// if header received |
|
|
|
|
|
if(m_SequenceInputDecoder.isHeaderReceived()) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
// if buffer received |
|
|
|
|
|
if(m_SequenceInputDecoder.isBufferReceived()) |
|
|
|
|
|
{ |
|
|
|
|
|
//check received stimulations on sequence input |
|
|
|
|
|
CStimulationSet* SequenceStimulationSet = m_SequenceInputDecoder.getOutputStimulationSet(); |
|
|
|
|
|
for(uint64_t j = 0; j < SequenceStimulationSet->size(); ++j) |
|
|
|
|
|
{ |
|
|
|
|
|
SequenceID = SequenceStimulationSet->getId(j); |
|
|
|
|
|
|
|
|
|
|
|
if(SequenceID >= m_RowBase && SequenceID < m_RowBase + m_nTactilos) |
|
|
|
|
|
{ |
|
|
|
|
|
Row = SequenceID - m_RowBase; |
|
|
|
|
|
IsTarget = (Row == (int)m_LastTarget); |
|
|
|
|
|
} |
|
|
|
|
|
if(SequenceID == OVTK_StimulationId_VisualStimulationStart) |
|
|
|
|
|
{ |
|
|
|
|
|
resetColor(); |
|
|
|
|
|
toggleFlashColor(Row); |
|
|
|
|
|
if (IsTarget) |
|
|
|
|
|
{ |
|
|
|
|
|
m_stimuliQueue.push_back(OVTK_StimulationId_Target); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
m_stimuliQueue.push_back(OVTK_StimulationId_NonTarget); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if(SequenceID == OVTK_StimulationId_VisualStimulationStop) |
|
|
|
|
|
{ |
|
|
|
|
|
resetColor(); |
|
|
|
|
|
} |
|
|
|
|
|
if(SequenceID == OVTK_StimulationId_SegmentStart) |
|
|
|
|
|
{ |
|
|
|
|
|
toggleLabelText(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
m_stimuliQueue.push_back(SequenceID); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if end received |
|
|
|
|
|
if(m_SequenceInputDecoder.isEndReceived()) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
boxContext.markInputAsDeprecated(0, i); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ Target stimulation |
|
|
|
|
|
for(uint64_t i = 0; i < boxContext.getInputChunkCount(1); ++i) |
|
|
|
|
|
{ |
|
|
|
|
|
if(m_LastTime >= boxContext.getInputChunkStartTime(1, i)) |
|
|
|
|
|
{ |
|
|
|
|
|
m_TargetInputDecoder.decode(i); |
|
|
|
|
|
|
|
|
|
|
|
// if header received |
|
|
|
|
|
if(m_SequenceInputDecoder.isHeaderReceived()) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
// if buffer received |
|
|
|
|
|
if(m_SequenceInputDecoder.isBufferReceived()) |
|
|
|
|
|
{ |
|
|
|
|
|
// check received dtimulations on Target input |
|
|
|
|
|
CStimulationSet* TargetStimulationSet = m_TargetInputDecoder.getOutputStimulationSet(); |
|
|
|
|
|
for(uint64_t j = 0; j < TargetStimulationSet->size(); ++j) |
|
|
|
|
|
{ |
|
|
|
|
|
TargetID = TargetStimulationSet->getId(j); |
|
|
|
|
|
|
|
|
|
|
|
if(TargetID >= m_RowBase && TargetID < m_RowBase + m_nTactilos) |
|
|
|
|
|
{ |
|
|
|
|
|
Row = TargetID - m_RowBase; |
|
|
|
|
|
TargetReceived = true; |
|
|
|
|
|
} |
|
|
|
|
|
if(TargetReceived) |
|
|
|
|
|
{ |
|
|
|
|
|
toggleTargetColor(Row); |
|
|
|
|
|
m_stimuliQueue.push_back(TargetID); |
|
|
|
|
|
|
|
|
|
|
|
std::string TargetLabel = gtk_label_get_text(m_TargetLabel); |
|
|
|
|
|
TargetLabel += gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[Row])))); |
|
|
|
|
|
gtk_label_set_text(m_TargetLabel, TargetLabel.c_str()); |
|
|
|
|
|
|
|
|
|
|
|
m_LastTarget = Row; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if end received |
|
|
|
|
|
if(m_SequenceInputDecoder.isEndReceived()) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
boxContext.markInputAsDeprecated(1, i); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ Result stimulation |
|
|
|
|
|
for(uint64_t i = 0; i < boxContext.getInputChunkCount(2); ++i) |
|
|
|
|
|
{ |
|
|
|
|
|
if(m_LastTime >= boxContext.getInputChunkStartTime(2, i)) |
|
|
|
|
|
{ |
|
|
|
|
|
m_ResultInputDecoder.decode(i); |
|
|
|
|
|
|
|
|
|
|
|
// if header received |
|
|
|
|
|
if(m_SequenceInputDecoder.isHeaderReceived()) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
// if buffer received |
|
|
|
|
|
if(m_SequenceInputDecoder.isBufferReceived()) |
|
|
|
|
|
{ |
|
|
|
|
|
// check received stimulations on result input |
|
|
|
|
|
CStimulationSet* ResultStimulationSet = m_ResultInputDecoder.getOutputStimulationSet(); |
|
|
|
|
|
for(uint64_t j = 0; j < ResultStimulationSet->size(); ++j) |
|
|
|
|
|
{ |
|
|
|
|
|
ResultID = ResultStimulationSet->getId(j); |
|
|
|
|
|
|
|
|
|
|
|
if(ResultID >= m_RowBase && ResultID < m_RowBase + m_nTactilos) |
|
|
|
|
|
{ |
|
|
|
|
|
Row = ResultID - m_RowBase; |
|
|
|
|
|
ResultReceived = true; |
|
|
|
|
|
} |
|
|
|
|
|
if(ResultReceived) |
|
|
|
|
|
{ |
|
|
|
|
|
toggleResultColor(Row); |
|
|
|
|
|
|
|
|
|
|
|
std::string ResultLabel = gtk_label_get_text(m_ResultLabel); |
|
|
|
|
|
ResultLabel += gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[Row])))); |
|
|
|
|
|
gtk_label_set_text(m_ResultLabel, ResultLabel.c_str()); |
|
|
|
|
|
|
|
|
|
|
|
//switch current menu ptr to submenu |
|
|
|
|
|
if(m_CurrMenu->get_SubMenu(Row) != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
m_CurrMenu = m_CurrMenu->get_SubMenu(Row); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if end received |
|
|
|
|
|
if(m_SequenceInputDecoder.isEndReceived()) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
// forward target stimulations |
|
|
|
|
|
boxContext.getInputChunk(2, i, ChunkStartTime, ChunkEndTime, Size, Buffer); |
|
|
|
|
|
boxContext.appendOutputChunkData(0, Buffer, Size); |
|
|
|
|
|
boxContext.markOutputAsReadyToSend(0, ChunkStartTime, ChunkEndTime); |
|
|
|
|
|
boxContext.markInputAsDeprecated(2, i); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------ Send accumulated stimuli to the acquisition server |
|
|
|
|
|
if(m_idleFuncTag == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
m_idleFuncTag = g_idle_add(FlushCB, this); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return(true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Function Definitions |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sends all accumulated stimuli to the TCP Tagging |
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::flushQueue() |
|
|
|
|
|
{ |
|
|
|
|
|
for (const auto& stimulation : m_stimuliQueue) |
|
|
|
|
|
{ |
|
|
|
|
|
m_stimulusSender->sendStimulation(stimulation); |
|
|
|
|
|
} |
|
|
|
|
|
m_stimuliQueue.clear(); |
|
|
|
|
|
|
|
|
|
|
|
// This function will be automatically removed after completion, so set to 0 |
|
|
|
|
|
m_idleFuncTag = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Change labels fore-/background |
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleFlashColor(uint64_t id) |
|
|
|
|
|
{ |
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_FlashFG); |
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_FlashBG); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleTargetColor(uint64_t id) |
|
|
|
|
|
{ |
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_TargetFG); |
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_TargetBG); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleResultColor(uint64_t id) |
|
|
|
|
|
{ |
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_ResultFG); |
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_ResultBG); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::resetColor() |
|
|
|
|
|
{ |
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[i])), GTK_STATE_NORMAL, &m_NoFlashFG); |
|
|
|
|
|
gtk_widget_modify_bg(m_EventBox[i], GTK_STATE_NORMAL, &m_NoFlashBG); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Change label text |
|
|
|
|
|
void CBoxAlgorithmP300TactileVisualization::toggleLabelText() |
|
|
|
|
|
{ |
|
|
|
|
|
for(uint64_t i = 0; i < m_nTactilos; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
std::string label_text = m_CurrMenu->get_LabelText(i); |
|
|
|
|
|
|
|
|
|
|
|
gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[i]))), label_text.c_str()); |
|
|
|
|
|
} |
|
|
} |
|
|
} |