diff --git a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp index 4ca66e2..f5964ec 100644 --- a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp +++ b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp @@ -1,469 +1,480 @@ -#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(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(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(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(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()); + } } \ No newline at end of file