123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- #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(5, &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());
- }
- }
|