diff --git a/CHANGELOG.txt b/CHANGELOG.txt
new file mode 100644
index 0000000..9dc3238
--- /dev/null
+++ b/CHANGELOG.txt
@@ -0,0 +1,65 @@
+-->TODO: -Interface Box erstellen(UDP,Serial,(BT),...)
+ -Offline Test
+ -Online Test
+
+06.05.2022:
+-->ui files für unterschiedliche Anzahl von Tactilos erstellt (p300-tactile-2.ui, p300-tactile-3.ui, ...)
+-->Lua files der szenarios angepasst, um die Variation der Tactiloanzahl zu ermöglichen
+-->arduino Firmware auf zehn mögliche Tactilos erweitert
+-->arduino Firmware ports angepasst (nutzung der PWM-fähigen ports)
+
+02.05.2022:
+-->FindThirdPartyBoost_System aus Cmakelist.txt entfernt (entfaellt mit OpenViBE3.3)
+-->Szenarios angepasst (einige Boxen wurden mit OpenViBE3.3 ueberarbeitet)
+-->UDPSender, TactileVisualization und TactiloStimulator Boxen erweitert um die Möglichkeit die Anzahl der Tactilos des Systems einzustellen
+
+28.02.2022:
+-->Box für die Ansteuerung der Tactilos über die Lattepanda GPIOs hinzugefügt
+
+11.02.2022:
+Änderungen am TactileBCI SourceCode:
+-->neue Box P300 Tactile Visualization für die Organisation von Menüs/Submenüs des Tactilen BCIs erstellt(Basierend auf der P300 Speller Visualization)
+
+-->Das LogLevel der Nachrichten in der UDPStimCodeSender Box auf Debug gesetzt um nicht standardmäßig die große Menge an Nachrichten anzuzeigen
+
+Änderungen an den Szenarios:
+-->In 1-Acquisition und 4-Online P300 Speller Visualization durch die neue Box P300 Tactile Visualization ersetzt
+
+Änderungen in OV_TACTILE.conf:
+-->Schriftgröße von Target, Flash und Selected angepasst
+
+
+
+05.02.2022:
+-->die verschiedenen repositories zu einem zusammengefasst
+
+
+
+29.01.2022:
+Änderungen an den Szenarios:
+1.Szenario Acquisition:
+-->Die Filterung des Signals erfolgt jetzt hier, statt in den Szenarien für die filterkonfiguration
+-->In der UI des Szenarios gibt es jetzt einen zweiten reiter zur anzeige des EEG-Signals
+
+2.Szenario Train xDAWN:
+-->Das aufgezeichnete signal ist jetzt bereits gefiltert, dementsprechend entfällt die filterung hier
+
+3.Szenario Train p300-classifier:
+-->Das aufgezeichnete signal ist jetzt bereits gefiltert, dementsprechend entfällt die filterung hier
+
+4.Szenario Online:
+-->Analog zu acquisition wird auch hier das gefilterte signal aufgezeichnet und nicht mehr das ungefilterte
+-->Auch hier lässt sich jetzt in einem zusätzlichen Reiter das EEG Signal anzeigen
+
+Änderungen an Scripts:
+p300-tactile-stimulator.lua:
+-->Da die Box derzeit keinen Input hat, wurde eine Zeile entfernt, welche die letzten erhaltenen daten löscht
+
+Änderungen an der UDPSender Box:
+-->Die weitergabe der Daten am boxoutput wurde verändert, um ein timingproblem zu beheben
+
+Änderungen im OpenVibe Sourcecode:
+\meta\sdk\plugins\processing\signal-processing\src\box-algorithms\ovpCBoxAlgorithmXDAWNTrainer.cpp:
+-->Z.338-339 geändert, damit die cfg mit gültigen werten gefüllt wird: fprintf(file, "\t%u\n", (unsigned int)m_filterDim);
+ fprintf(file, "\t%u\n", (unsigned int)nChannel);
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4a4d440
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,46 @@
+if(OV_DISABLE_GTK)
+ message(STATUS "Skipping Plugins: Simple Visualization, no GTK")
+ return()
+endif(OV_DISABLE_GTK)
+
+project(openvibe-plugins-tactile-bci VERSION ${OPENVIBE_MAJOR_VERSION}.${OPENVIBE_MINOR_VERSION}.${OPENVIBE_PATCH_VERSION})
+
+file(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.inl)
+
+add_library(${PROJECT_NAME} SHARED ${SRC_FILES})
+
+target_link_libraries(${PROJECT_NAME}
+ openvibe
+ openvibe-common
+ openvibe-toolkit
+ openvibe-module-ebml
+ openvibe-module-system
+ openvibe-visualization-toolkit
+)
+
+set_target_properties(${PROJECT_NAME} PROPERTIES
+ VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_VERSION_MAJOR}
+ FOLDER ${PLUGINS_FOLDER}
+ COMPILE_FLAGS "-DOVP_Exports -DOVP_Shared")
+
+add_definitions(-DTARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines)
+add_definitions(-DBOOST_DATE_TIME_NO_LIB)
+if(WIN32)
+ add_definitions(-D_WIN32_WINNT=0x0501)
+endif(WIN32)
+
+include("FindOpenViBEModuleTCPTagging")
+include("FindThirdPartyGTK")
+# need boost for UDPStimcodeSender and TactileStimulation
+include("FindThirdPartyBoost")
+
+# -----------------------------
+# Install files
+# -----------------------------
+install(TARGETS ${PROJECT_NAME}
+ RUNTIME DESTINATION ${DIST_BINDIR}
+ LIBRARY DESTINATION ${DIST_LIBDIR}
+ ARCHIVE DESTINATION ${DIST_LIBDIR})
+
+install(DIRECTORY scenarios/ DESTINATION ${DIST_DATADIR}/openvibe/thn_bci/scenarios)
diff --git a/Find_gUSBAmp/FindThirdPartyGUSBampCAPI.cmake b/Find_gUSBAmp/FindThirdPartyGUSBampCAPI.cmake
deleted file mode 100644
index 9553dd5..0000000
--- a/Find_gUSBAmp/FindThirdPartyGUSBampCAPI.cmake
+++ /dev/null
@@ -1,64 +0,0 @@
-# ---------------------------------
-# Finds GUSBampCAPI
-# Adds library to target
-# Adds include path
-# ---------------------------------
-
-GET_PROPERTY(OV_PRINTED GLOBAL PROPERTY OV_TRIED_ThirdPartyGUSBampCAPI)
-
-IF(WIN32)
- IF("${PLATFORM_TARGET}" STREQUAL "x64")
- SET(GUSBAMP_ARCH "x64")
- ELSE()
- SET(GUSBAMP_ARCH "Win32")
- ENDIF()
-
- FIND_PATH(PATH_GUSBampCAPI gUSBamp.h PATHS
- "C:/Program Files/gtec/gUSBampCAPI/API"
- "C:/Program Files (x86)/gtec/gUSBampCAPI/API"
- "C:/Program Files/gtec/gUSBampCAPI/API/${GUSBAMP_ARCH}"
- "C:/Program Files (x86)/gtec/gUSBampCAPI/API/${GUSBAMP_ARCH}"
- ${LIST_DEPENDENCIES_PATH})
- IF(PATH_GUSBampCAPI)
- OV_PRINT(OV_PRINTED " Found gtec gUSBampCAPI...")
- INCLUDE_DIRECTORIES(${PATH_GUSBampCAPI})
- FIND_LIBRARY(LIB_GUSBampCAPI gUSBamp PATHS ${PATH_GUSBampCAPI})
- IF(LIB_GUSBampCAPI)
- OV_PRINT(OV_PRINTED " [ OK ] lib ${LIB_GUSBampCAPI}")
- TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_GUSBampCAPI} )
- ELSE(LIB_GUSBampCAPI)
- OV_PRINT(OV_PRINTED " [FAILED] lib gUSBamp")
- ENDIF(LIB_GUSBampCAPI)
-
- # Copy the DLL file at install
- INSTALL(PROGRAMS "${PATH_GUSBampCAPI}/gUSBamp.dll" DESTINATION ${DIST_BINDIR})
-
- ADD_DEFINITIONS(-DTARGET_HAS_ThirdPartyGUSBampCAPI)
- SET(OV_ThirdPartyGUSBAmp "YES")
-
- ELSE()
- OV_PRINT(OV_PRINTED " FAILED to find gtec gUSBampCAPI (optional driver)")
- ENDIF()
-ENDIF(WIN32)
-
-
-IF(UNIX)
- # To try other versions of the gtec's library, change the number below
- SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so.1.16")
- SET(CMAKE_FIND_LIBRARY_PREFIXES "lib")
- FIND_LIBRARY(gUSBAmpLinux_LIBRARY NAMES "gUSBampAPIso" PATHS "/usr/lib" "/usr/local/lib")
- IF(gUSBAmpLinux_LIBRARY)
- OV_PRINT(OV_PRINTED " Found gtec gUSBAmpAPILinux...")
- OV_PRINT(OV_PRINTED " [ OK ] Third party lib ${gUSBAmpLinux_LIBRARY}")
- ADD_DEFINITIONS(-DTARGET_HAS_ThirdPartyGUSBampCAPI_Linux)
- TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${gUSBAmpLinux_LIBRARY} )
- SET(OV_ThirdPartyGUSBAmp "YES")
- ELSE()
- OV_PRINT(OV_PRINTED " FAILED to find gtec gUSBAmpAPI Linux... (optional)")
- OV_PRINT(OV_PRINTED " : If it should be found, see that 'libgusbampapi.so.1.16' link exists on the fs, with no further nemeric suffixes in the filename.")
- OV_PRINT(OV_PRINTED " : e.g. do 'cd /usr/lib/ ; ln -s libgusbampapi.so.1.16'. See gtec-bcilab/README for details.")
- ENDIF()
-ENDIF(UNIX)
-
-SET_PROPERTY(GLOBAL PROPERTY OV_TRIED_ThirdPartyGUSBampCAPI "Yes")
-
diff --git a/GUSBamp_Driver/Queue.h b/GUSBamp_Driver/Queue.h
deleted file mode 100644
index c05d953..0000000
--- a/GUSBamp_Driver/Queue.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#pragma once
-
-#if defined TARGET_HAS_ThirdPartyGUSBampCAPI_Linux
-
-#include
-#include
-
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef MAX
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-template
-class Queue
-{
- T* buffer = nullptr;
- int head = 0, tail = 0, size = 0;
-
-public:
- Queue() { }
-
- Queue(T* array, const int len)
- {
- size = len;
- buffer = array;
- }
-
- void SetBuffer(T* array, const int len)
- {
- size = len;
- head = tail = 0;
- buffer = array;
- }
-
- int Get(T* elements, int len)
- {
- // Trim the length if necessary to only as large as the number of available elements in the buffer
- len = MIN(len, Avail());
-
- int nonwrapped = MIN((size - tail), len);
- const int wrapped = len - nonwrapped;
-
- // memcpy the data starting at the head all the way up to the last element *(storage - 1)
- memcpy(elements, (buffer + tail), nonwrapped * sizeof(T));
-
- // If there's still data to copy memcpy whatever remains, starting at the first element *(begin) until the end of data. The first step will have ensured
- // that we don't crash into the tail during this process.
- memcpy((elements + nonwrapped), buffer, wrapped * sizeof(T));
-
- // Recalculate head
- tail = (tail + nonwrapped + wrapped) % size;
-
- return len;
- }
-
- // Returns the number of bytes actually placed in the array
- int Put(const T* elements, int len)
- {
- // Trim the length if necessary to only as large as the nuber of free elements in the buffer
- len = MIN(len, Free());
-
- // Figure out how much to append to the end of the buffer and how much will overlap onto the start
- int nonwrapped = MIN((size - head), len);
- const int wrapped = len - nonwrapped;
-
- // memcpy the data starting at the head all the way up to the last element *(storage - 1)
- memcpy((buffer + head), elements, nonwrapped * sizeof(T));
-
- // If there's still data to copy memcpy whatever remains onto the beginning of the array
- memcpy(buffer, (elements + nonwrapped), wrapped * sizeof(T));
-
- // Re-recalculate head
- head = (head + nonwrapped + wrapped) % size;
-
- return len;
- }
-
- // Expand the size of queue without actually modifying any of the contents - useful for copying directly onto the queu buffer
- int Pad(int len)
- {
- // Trim the length if necessary to only as large as the nuber of free elements in the buffer
- len = MIN(len, Free());
-
- // Figure out how much to append to the end of the buffer and how much will overlap onto the start
- const int nonwrapped = MIN((size - head), len), wrapped = len - nonwrapped;
-
- // Re-recalculate head
- head = (head + nonwrapped + wrapped) % size;
-
- return len;
- }
-
- // Removes the oldest entry from the Queue
- void Pop() { if (Avail()) tail = (tail + 1) % size; }
-
- // Returns the oldest element in the array (the one added before any other)
- T& Tail() { return buffer[tail]; }
-
- // Returns the newest element in the array (the one added after every other)
- T& Head() { return buffer[(head + size - 1) % size]; }
-
- T& operator[](int n) { return buffer[tail + n % size]; }
-
- void Clear() { head = tail = 0; }
-
- int Avail() const { return (size + head - tail) % size; }
-
- int Free() const { return (size - 1 - Avail()); }
-
- // Gets the number of free elements that can be stored contiguously
- int FreeContiguous() { return head < tail ? tail - head - 1 : MIN(size - head, Free()); }
-
- // Gets a pointer to the next free address in the buffer
- T* NextFreeAddress() { return buffer + head; }
-};
-
-#endif // TARGET_HAS_ThirdPartyGUSBampCAPI_Linux
diff --git a/GUSBamp_Driver/ovasCDriverGTecGUSBampLinux.cpp b/GUSBamp_Driver/ovasCDriverGTecGUSBampLinux.cpp
deleted file mode 100644
index 06113fb..0000000
--- a/GUSBamp_Driver/ovasCDriverGTecGUSBampLinux.cpp
+++ /dev/null
@@ -1,353 +0,0 @@
-#if defined TARGET_HAS_ThirdPartyGUSBampCAPI_Linux
-
-#include "ovasCDriverGTecGUSBampLinux.h"
-
-#include
-
-namespace OpenViBE {
-namespace AcquisitionServer {
-
-CDriverGTecGUSBampLinux::CDriverGTecGUSBampLinux(IDriverContext& ctx)
- : IDriver(ctx), m_settings("AcquisitionServer_Driver_GTecGUSBampLinux", m_driverCtx.getConfigurationManager()),
- m_nSamplePerSentBlock(0), m_sampleSend(nullptr), m_sampleReceive(nullptr), m_sampleBuffer(nullptr), m_currentSample(0), m_currentChannel(0)
-{
- // Default values
- m_header.setSamplingFrequency(512);
- m_header.setChannelCount(8);
-
- m_config.ao_config = &m_analogOutConfig;
-
- // Configure some defaults so the settings are reasonable as soon as the driver loads and the user can tweak them from there
-
- // Configure the analog waveform to be created by the internal signal generator
- m_analogOutConfig.shape = GT_ANALOGOUT_SINE;
- m_analogOutConfig.frequency = 1;
- m_analogOutConfig.amplitude = 0;
- m_analogOutConfig.offset = 0;
-
- // This pretty much has to be GT_NOS_AUTOSET, don't know why, so says the documentation
- m_config.number_of_scans = GT_NOS_AUTOSET;
- // Disable the trigger line, digital io scan, slave mode and the shortcut
- m_config.enable_trigger_line = GT_FALSE;
- m_config.scan_dio = GT_FALSE;
- m_config.slave_mode = GT_FALSE;
- m_config.enable_sc = GT_FALSE;
-
- // Set the mode to just take readings
- m_config.mode = GT_MODE_NORMAL;
-
- // Set all the blocks A-D to use the common ground and reference voltages
- for (uint32_t i = 0; i < GT_USBAMP_NUM_GROUND; ++i)
- {
- m_config.common_ground[i] = GT_TRUE;
- m_config.common_reference[i] = GT_TRUE;
- }
-
- // Configure each input
- for (unsigned char i = 0; i < GT_USBAMP_NUM_ANALOG_IN; ++i)
- {
- // Should be from 1 - 16, specifies which channel to observe as input i
- m_config.analog_in_channel[i] = i + 1;
- // Don't use any of the filters on channel i
- m_config.bandpass[i] = GT_FILTER_NONE;
- // Don't use any of the notch filters on channel i
- m_config.notch[i] = GT_FILTER_NONE;
- // Don't use any of the other channels for bi-polar derivation
- m_config.bipolar[i] = GT_BIPOLAR_DERIVATION_NONE;
- }
-
- // Now look for any connected devices. If any exist we'll set the name to the first one found
- char** devices = nullptr;
- size_t nDevice = 0;
-
- // Refresh and get the list of currently connnected devices
- GT_UpdateDevices();
- nDevice = GT_GetDeviceListSize();
- devices = GT_GetDeviceList();
-
- // If any devices were found at all, set the combo box to the first one listed
- if (nDevice) { m_deviceName = devices[0]; }
-
- GT_FreeDeviceList(devices, nDevice);
-
- // Now retrieve all those configs from the settings file if they are there to be found (don't need to worry about sample rate or channel number though since they're already in the header)
- /*m_settings.add("Header", &m_header);
- m_settings.add("DeviceName", static_cast(&m_deviceName));
- m_settings.add("Mode", static_cast(&m_config.mode));
- m_settings.add("EnableTrigger", static_cast(&m_config.enable_trigger_line));
- m_settings.add("ScanDIO", static_cast(&m_config.scan_dio));
- m_settings.add("SlaveMode", static_cast(&m_config.slave_mode));
- m_settings.add("EnableShortcut", static_cast(&m_config.enable_sc));
- m_settings.add("AnalogOutShape", static_cast(&m_analogOutConfig.shape));
- m_settings.add("AnalogOutFrequency", static_cast(&m_analogOutConfig.frequency));
- m_settings.add("AnalogOutAmplitude", static_cast(&m_analogOutConfig.amplitude));
- m_settings.add("AnalogOutOffset", static_cast(&m_analogOutConfig.offset));*/
-
- /*// Set all the blocks A-D to use the common ground and reference voltages
- for (uint32_t i = 0; i < GT_USBAMP_NUM_GROUND; ++i)
- {
- std::stringstream gndConfigName, configName;
- gndConfigName << "CommonGround" << i;
- configName << "CommonReference" << i;
- m_settings.add(gndConfigName.str().c_str(), static_cast(&m_config.common_ground[i]));
- m_settings.add(configName.str().c_str(), static_cast(&m_config.common_reference[i]));
- }*/
-
- /*// Configure each input
- for (uint32_t i = 0; i < GT_USBAMP_NUM_ANALOG_IN; ++i)
- {
- std::stringstream bandpassConfigName, notchConfigName, bipolarConfigName;
- bandpassConfigName << "Bandpass" << i;
- notchConfigName << "Notch" << i;
- bipolarConfigName << "Bipolar" << i;
- m_settings.add(bandpassConfigName.str().c_str(), static_cast(&m_config.bandpass[i]));
- m_settings.add(notchConfigName.str().c_str(), static_cast(&m_config.notch[i]));
- m_settings.add(bipolarConfigName.str().c_str(), static_cast(&m_config.bipolar[i]));
- }*/
-
- // This restores saved settings if any, such as sampling rate
- m_settings.load();
-
- // Set the sampling rate that may have been changed by load
- m_config.sample_rate = m_header.getSamplingFrequency();
-
- // Number of channels that may have been changed by load
- m_config.num_analog_in = m_header.getChannelCount();
-}
-
-//___________________________________________________________________//
-// //
-
-bool CDriverGTecGUSBampLinux::initialize(const uint32_t nSamplePerSentBlock, IDriverCallback& callback)
-{
- if (m_driverCtx.isConnected()) return false;
- if (!m_header.isChannelCountSet() || !m_header.isSamplingFrequencySet()) return false;
-
- // If the scan digital inputs flag is set, the API will return one extra channel outside of the analog data requested, so we need to match that on the header
- if (m_config.scan_dio == GT_TRUE)
- {
- m_header.setChannelCount(m_config.num_analog_in + 1);
- m_header.setChannelName(m_config.num_analog_in, "Digital");
- }
-
- // Allocate buffers for...
-
- // Sending to OpenViBE
- m_sampleSend = new float[m_header.getChannelCount() * nSamplePerSentBlock];
- // Receiving from the hardware,
- m_sampleReceive = new float[m_header.getChannelCount() * nSamplePerSentBlock];
- // Storing the data so we pass it between the two threads - we're using the recommended buffer size put out by gtec, which is enormous
- m_sampleBuffer = new float[GT_USBAMP_RECOMMENDED_BUFFER_SIZE / sizeof(float)];
-
- // Set up the queue to help pass the data out of the hardware thread
- m_sampleQueue.SetBuffer(m_sampleBuffer, m_header.getChannelCount() * m_header.getSamplingFrequency() / 8);
-
- // If any of that allocation fails then give up. Not sure what setting it all to NULL is for, but we'll go with it.
- if (!m_sampleSend || !m_sampleReceive || !m_sampleBuffer)
- {
- delete[] m_sampleSend;
- delete[] m_sampleReceive;
- delete[] m_sampleBuffer;
- m_sampleSend = m_sampleReceive = m_sampleBuffer = nullptr;
-
- return false;
- }
-
- // Apparently this causes the API to print debug info to the console, I'm yet to see any though
- GT_ShowDebugInformation(GT_TRUE);
-
- // Try to open the device with the configured name, let the user know how it goes
- if (!GT_OpenDevice(m_deviceName.c_str()))
- {
- m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "Could not open device: " << m_deviceName << "\n";
- return false;
- }
-
- if (!GT_SetConfiguration(m_deviceName.c_str(), &m_config))
- {
- m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "Could not apply configuration to device: " << m_deviceName << "\n";
- return false;
- }
-
- GT_SetDataReadyCallBack(m_deviceName.c_str(), &OnDataReady, static_cast(this));
-
- // Saves parameters
- m_callback = &callback;
- m_nSamplePerSentBlock = nSamplePerSentBlock;
-
- return true;
-}
-
-bool CDriverGTecGUSBampLinux::start()
-{
- if (!m_driverCtx.isConnected()) return false;
- if (m_driverCtx.isStarted()) return false;
-
- // ...
- // request hardware to start
- // sending data
- // ...
-
- // Need to reset these in case the device is stopped mid-sample and then started again
- m_currentChannel = m_currentSample = 0;
-
- GT_StartAcquisition(m_deviceName.c_str());
-
- m_driverCtx.getLogManager() << Kernel::LogLevel_Info << "Acquisition Started\n";
-
- return true;
-}
-
-// So when the gtec buffer grows larger than a send buffer, copy it all to a send buffer sized array, then copy it into the actual send buffer one by one.
-bool CDriverGTecGUSBampLinux::loop()
-{
- if (!m_driverCtx.isConnected()) return false;
- if (!m_driverCtx.isStarted()) return true;
-
- const CStimulationSet stimSet;
-
- // while there's new data available on the queue
- while (m_sampleQueue.Avail())
- {
- // take it off and put it in the appropriate element in the outgoing buffer
- m_sampleQueue.Get(m_sampleSend + m_currentChannel * m_nSamplePerSentBlock + m_currentSample, 1);
-
- // Increment the current channel
- m_currentChannel++;
-
- // If the current channel reaches the channel count then move to the next sample
- if (m_currentChannel == m_header.getChannelCount())
- {
- m_currentChannel = 0;
- m_currentSample++;
- }
-
- // If the sample count reaches the number per sent block, then send it and start again
- if (m_currentSample == m_nSamplePerSentBlock)
- {
- m_callback->setSamples(m_sampleSend); // it looks as if this copies the buffer, so we're free modify it as soon as it executes
-
- // 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);
-
- m_currentSample = 0;
- }
- }
-
- return true;
-}
-
-bool CDriverGTecGUSBampLinux::stop()
-{
- if (!m_driverCtx.isConnected()) return false;
- if (!m_driverCtx.isStarted()) return false;
-
- // ...
- // request the hardware to stop
- // sending data
- // ...
- GT_StopAcquisition(m_deviceName.c_str());
- m_driverCtx.getLogManager() << Kernel::LogLevel_Info << "Acquisition Stopped";
-
- return true;
-}
-
-bool CDriverGTecGUSBampLinux::uninitialize()
-{
- if (!m_driverCtx.isConnected()) return false;
- if (m_driverCtx.isStarted()) return false;
-
- GT_CloseDevice(m_deviceName.c_str());
-
- m_driverCtx.getLogManager() << Kernel::LogLevel_Info << "Closed Device: " << m_deviceName << "\n";
-
- // ...
- // uninitialize hardware here
- // ...
- m_sampleQueue.SetBuffer(nullptr, 0);
-
- delete[] m_sampleSend;
- delete[] m_sampleBuffer;
- delete[] m_sampleReceive;
-
- m_sampleSend = m_sampleReceive = m_sampleBuffer = nullptr;
-
- m_callback = nullptr;
-
- return true;
-}
-
-//___________________________________________________________________//
-// //
-bool CDriverGTecGUSBampLinux::isConfigurable()
-{
- return false; // change to false if your device is not configurable
-}
-
-bool CDriverGTecGUSBampLinux::configure()
-{
- /*// Change this line if you need to specify some references to your driver attribute that need configuration, e.g. the connection ID.
- CConfigurationGTecGUSBampLinux config(m_driverCtx, Directories::getDataDir() + "/applications/acquisition-server/interface-GTecGUSBampLinux.ui", &m_deviceName, &m_config);
-
- if (!config.configure(m_header)) { return false; }
-
- m_header.setChannelCount(m_config.num_analog_in);
- m_header.setSamplingFrequency(m_config.sample_rate);
-
- m_settings.save();*/
-
- return true;
-}
-
-/*void AcquisitionServer::OnDataReady(void *param)
-{
- // Like the 'this' pointer, but for a friend function
- CDriverGTecGUSBampLinux *that = (CDriverGTecGUSBampLinux*)param;
-
- // This is pretty tricky to know in advance, the API decides how many values to spit out depnding on a few factors it seems.
- // We'll allocate a reasonble buffer and call GT_GetData as many times as is necessary
- while(size_t nSamplesToRead = GT_GetSamplesAvailable(that->m_deviceName.c_str()))
- {
- // If there are more samples than will fit in the buffer, just get as many as possible and we can get the rest next iteration
- if(nSamplesToRead > CDriverGTecGUSBampLinux::ReceiveBufferSize * sizeof(float))
- nSamplesToRead = CDriverGTecGUSBampLinux::ReceiveBufferSize * sizeof(float);
-
- // Get the data -- TODO: rewrite this algorithm such that we can copy directly from GT_GetData into the buffer read in the loop() function - is this a bug?? Maybe, but probably not since the calibration mode was always perfect
- GT_GetData(that->m_deviceName.c_str(), reinterpret_cast(that->m_sampleReceive), nSamplesToRead);
-
- // Put it on the sample queue
- that->m_sampleQueue.Put(that->m_sampleReceive, nSamplesToRead / sizeof(float));
- }
-}*/
-
-void OnDataReady(void* param)
-{
- // Like the 'this' pointer, but for a friend function
- CDriverGTecGUSBampLinux* that = static_cast(param);
-
- // This is pretty tricky to know in advance, the API decides how many values to spit out depnding on a few factors it seems.
- // We'll allocate a reasonble buffer and call GT_GetData as many times as is necessary
- while (size_t samplesToRead = GT_GetSamplesAvailable(that->m_deviceName.c_str()))
- {
- // If there are more samples than will fit in the buffer, just get as many as possible and we can get the rest next iteration
- if (samplesToRead > that->m_sampleQueue.FreeContiguous() * sizeof(float)) samplesToRead = that->m_sampleQueue.FreeContiguous() * sizeof(float);
-
- // Get the data and put it directly onto the queue
- GT_GetData(that->m_deviceName.c_str(), reinterpret_cast(that->m_sampleQueue.NextFreeAddress()), samplesToRead);
-
- // Pad the queue so it recognises how much data was just added to it
- that->m_sampleQueue.Pad(samplesToRead / sizeof(float));
- }
-}
-
-} // namespace AcquisitionServer
-} // namespace OpenViBE
-#endif // TARGET_HAS_ThirdPartyGUSBampCAPI_Linux
diff --git a/GUSBamp_Driver/ovasCDriverGTecGUSBampLinux.h b/GUSBamp_Driver/ovasCDriverGTecGUSBampLinux.h
deleted file mode 100644
index 6740ee5..0000000
--- a/GUSBamp_Driver/ovasCDriverGTecGUSBampLinux.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#pragma once
-
-#if defined TARGET_HAS_ThirdPartyGUSBampCAPI_Linux
-
-#include "ovasIDriver.h"
-#include "../ovasCHeader.h"
-#include
-
-#include "../ovasCSettingsHelper.h"
-#include "../ovasCSettingsHelperOperators.h"
-
-#include
-#include "Queue.h"
-
-namespace OpenViBE {
-namespace AcquisitionServer {
-void OnDataReady(void* param);
-
-/**
- * \class CDriverGTecGUSBampLinux
- * \author Tom Stewart (University of Tsukuba)
- * \date Mon Feb 9 18:59:22 2015
- * \brief The CDriverGTecGUSBampLinux allows the acquisition server to acquire data from a g.tec g.USBamp from Linux.
- *
- * \sa CConfigurationGTecGUSBampLinux
- */
-class CDriverGTecGUSBampLinux final : public IDriver
-{
- static const int ReceiveBufferSize = 8192;
-public:
- friend void OnDataReady(void* param);
-
- explicit CDriverGTecGUSBampLinux(IDriverContext& ctx);
- ~CDriverGTecGUSBampLinux() override {}
- const char* getName() override { return "g.tec g.USBamp Linux BCI-Lab"; }
-
- bool initialize(const uint32_t nSamplePerSentBlock, IDriverCallback& callback) override;
- bool uninitialize() override;
-
- bool start() override;
- bool stop() override;
- bool loop() override;
-
- bool isConfigurable() override;
- bool configure() override;
- const IHeader* getHeader() override { return &m_header; }
-
- bool isFlagSet(const EDriverFlag flag) const override { 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;
-
- uint32_t m_nSamplePerSentBlock;
-
- float *m_sampleSend, *m_sampleReceive, *m_sampleBuffer;
- Queue m_sampleQueue;
-private:
-
- /*
- * Insert here all specific attributes, such as USB port number or device ID.
- */
- std::string m_deviceName;
- gt_usbamp_config m_config;
- gt_usbamp_analog_out_config m_analogOutConfig;
-
- // Keeps track of where we are with filling up the buffer
- uint32_t m_currentSample, m_currentChannel;
-};
-} // namespace AcquisitionServer
-} // namespace OpenViBE
-
-#endif // TARGET_HAS_ThirdPartyGUSBampCAPI_Linux
diff --git a/README.md b/README.md
index 9a4959b..4c3aed2 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,24 @@
-# g.USBamp Linux
+# TactileBCI
-### **Find gUSBamp:**
-Das CMake Modul FindThirdPartyGUSBampCAPI.cmake wurde für die zur Verfügung gestellte neue Version der gUSBamp C-API für Linux angepasst. Benötigt werden zur Verwendung die [Version 1.16 der API](https://www.dropbox.com/sh/5ru6suscpz9kh5a/AAAawMPWfLhPCI9EyGyyX1Jsa?dl=0) und die [Boost Library version 1.58](https://www.boost.org/users/history/version_1_58_0.html).
+Enthält alle für das Taktile BCI der THN benötigten Box-Codes und Designer-Szenarien, sowie eine Anleitung zu deren Verwendung (s. TactileBCI/scenarios/manuals/).
-Das angepasste MakeFile muss vor dem Compilieren nach "/meta/extras/cmake-modules/"
+Bei diesem taktilen BCI der THN, haben wir ein Hauptmenü mit 6 Elementen wovon 4 in untermenüs führen und die anderen 2 die antwortmöglichkeiten ja/nein darstellen.
-### **gUSBamp_Driver:**
+Dabei wird jeder Menüpunkt von einem kleinen Vibrationsmotor ("Tactilo") repräsentiert.
-Anspassung für den BCILAB Treiber für das gUSBamp.
+Die Tactilos werden, über eine festgelegte Anzahl von Wiederholungen und Trials, in zufälliger Reihenfolge angesteuert um so sensorisch ein P300-Signal zu erzeugen.
-Vor dem Kompilieren nach "/meta/extras/contrib/plugins/server-drivers/gtec-bcilab/src/" kopieren.
\ No newline at end of file
+Mit dieser vorgehensweise soll es möglich gemacht werden durch die Menüs der UI zu navigieren.
+
+---------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+Verwendung:
+
+**WICHTIG:** Das Plugin ist fuer die Verwendung mit OpenViBE 3.3 gemacht
+
+1) git clone https://git.efi.th-nuernberg.de/gitea/baumannto57992/TactileBCI/
+
+2) das erstellte verzeichniss "TactileBCI" nach /meta/extras/plugins/processing/ kopieren
+
+3) Danach OpenViBE kompilieren
diff --git a/arduino/README.md b/arduino/README.md
new file mode 100644
index 0000000..e0b0ddb
--- /dev/null
+++ b/arduino/README.md
@@ -0,0 +1,3 @@
+# TactiloControllerPanda
+Dieses Programm empfaengt Daten von der Korrespondierenden OpenViBE Box ueber eine serielle Schnittstelle.
+Auf Basis der erhaltenen Daten, werden die bis zu zehn Tactilos des Taktilen Brain Computer Interface angesteuert. Das Timing wird dabei komplett von OpenViBE uebernommen.
diff --git a/arduino/TactiloControllerPanda.ino b/arduino/TactiloControllerPanda.ino
new file mode 100644
index 0000000..ef16498
--- /dev/null
+++ b/arduino/TactiloControllerPanda.ino
@@ -0,0 +1,144 @@
+
+///-------------------------------------------------------------------------------------------------
+///
+/// \file TactiloControllerPanda.ino
+/// \brief Controlls the Tactilos on the Leonardos GPIOs, based on the messages from OpenVibes TactiloController Box Algorithm
+/// Hochladen mit der Arduino IDE
+/// \author Tobias Baumann (TH-Nürnberg).
+/// \version 1.0.
+/// \date Mon Mar 7 14:02:56 2022.
+///
+///-------------------------------------------------------------------------------------------------
+
+//define used GPIO pins
+#define TAC1 13 //PWM
+#define TAC2 11 //PWM
+#define TAC3 10 //PWM
+#define TAC4 9 //PWM
+#define TAC5 6 //PWM
+#define TAC6 5 //PWM
+//reserve
+#define TAC7 3 //PWM
+#define TAC8 2
+#define TAC9 1
+#define TAC10 0
+
+
+
+void setup()
+{
+ //init serial
+ Serial.begin(115200);
+
+ //init GPIOs
+ Serial.println("...init GPIOs");
+ set_PinMode();
+ set_AllLow();
+}
+
+void loop()
+{
+ char SerialData;
+
+ if(Serial.available() > 0)
+ {
+ SerialData = Serial.read();
+ processSerialData(SerialData);
+ }
+}
+
+void set_PinMode()
+{
+ //set all pins to OUTPUT
+ pinMode(TAC1, OUTPUT);
+ pinMode(TAC2, OUTPUT);
+ pinMode(TAC3, OUTPUT);
+ pinMode(TAC4, OUTPUT);
+ pinMode(TAC5, OUTPUT);
+ pinMode(TAC6, OUTPUT);
+ pinMode(TAC7, OUTPUT);
+ pinMode(TAC8, OUTPUT);
+ pinMode(TAC9, OUTPUT);
+ pinMode(TAC10, OUTPUT);
+}
+
+void set_AllLow()
+{
+ //set all pins to LOW
+ digitalWrite(TAC1, LOW);
+ digitalWrite(TAC2, LOW);
+ digitalWrite(TAC3, LOW);
+ digitalWrite(TAC4, LOW);
+ digitalWrite(TAC5, LOW);
+ digitalWrite(TAC6, LOW);
+ digitalWrite(TAC7, LOW);
+ digitalWrite(TAC8, LOW);
+ digitalWrite(TAC9, LOW);
+ digitalWrite(TAC10, LOW);
+}
+
+void processSerialData(char SerialData)
+{
+ switch(SerialData)
+ {
+ case '0':
+ digitalWrite(TAC1, !digitalRead(TAC1));
+ //Serial.print("Tactilo 1: ");
+ //Serial.println(digitalRead(TAC1));
+ break;
+ case '1':
+ digitalWrite(TAC2, !digitalRead(TAC2));
+ //Serial.print("Tactilo 2: ");
+ //Serial.println(digitalRead(TAC2));
+ break;
+ case '2':
+ digitalWrite(TAC3, !digitalRead(TAC3));
+ //Serial.print("Tactilo 3: ");
+ //Serial.println(digitalRead(TAC3));
+ break;
+ case '3':
+ digitalWrite(TAC4, !digitalRead(TAC4));
+ //Serial.print("Tactilo 4: ");
+ //Serial.println(digitalRead(TAC4));
+ break;
+ case '4':
+ digitalWrite(TAC5, !digitalRead(TAC5));
+ //Serial.print("Tactilo 5: ");
+ //Serial.println(digitalRead(TAC5));
+ break;
+ case '5':
+ digitalWrite(TAC6, !digitalRead(TAC6));
+ //Serial.print("Tactilo 6: ");
+ //Serial.println(digitalRead(TAC6));
+ break;
+ case '6':
+ digitalWrite(TAC7, !digitalRead(TAC7));
+ //Serial.print("Tactilo 7: ");
+ //Serial.println(digitalRead(TAC7));
+ break;
+ case '7':
+ digitalWrite(TAC8, !digitalRead(TAC8));
+ //Serial.print("Tactilo 8: ");
+ //Serial.println(digitalRead(TAC8));
+ break;
+ case '8':
+ digitalWrite(TAC9, !digitalRead(TAC9));
+ //Serial.print("Tactilo 9: ");
+ //Serial.println(digitalRead(TAC9));
+ break;
+ case '9':
+ digitalWrite(TAC10, !digitalRead(TAC10));
+ //Serial.print("Tactilo 10: ");
+ //Serial.println(digitalRead(TAC10));
+ break;
+ case 'b':
+ Serial.println("...Begin Tactile Session");
+ break;
+ case 'e':
+ set_AllLow();
+ Serial.println("...End Tactile Session");
+ break;
+ default:
+ break;
+ }
+}
diff --git a/scenarios/cfg/OV_TACTILE_PANDA.conf b/scenarios/cfg/OV_TACTILE_PANDA.conf
new file mode 100644
index 0000000..3900f93
--- /dev/null
+++ b/scenarios/cfg/OV_TACTILE_PANDA.conf
@@ -0,0 +1,124 @@
+########################################################################################################################
+# This configuration file contains declarations of variables used by the scenarios of the tactile BCI System #
+# #
+# Add --config PATH_TO_THIS_FILE when starting the designer from the command line #
+# USE --define TOKEN VALUE to assign a different value to a token without changing the default configuration #
+# #
+# #
+# Scenarios requiring this configuration file: p300-tactile-0-signal-monitoring.xml, p300-tactile-1-acquisition.xml, #
+# p300-tactile-2-train-xDAWN.xml, p300-tactile-3-train-classifier.xml, #
+# p300-tactile-4-online.xml #
+# #
+# Author : Tobias Baumann #
+# Date : 2021-12-27 #
+########################################################################################################################
+
+
+########################################################################################################################
+# General Settings #
+########################################################################################################################
+PATH_CONFIG = ${Player_ScenarioDirectory}/cfg
+PATH_SCRIPTS = ${Player_ScenarioDirectory}/scripts
+PATH_SIGNALS = ${Player_ScenarioDirectory}/signals
+PATH_UI = ${Player_ScenarioDirectory}/ui
+
+ROW_BASE = OVTK_StimulationId_Label_01
+N_TACTILOS = 6
+FREE_SPELLING = true
+
+
+########################################################################################################################
+# Acquisition and Signal Processing #
+########################################################################################################################
+ACQUISITION_SERVER_HOST_NAME = ${AcquisitionServer_HostName}
+ACQUISITION_SERVER_PORT = 1024
+CHANNEL_SELECTION = 1;2;3;4;5;6;7;8
+SIGNAL_DECIMATION_FACTOR = 2
+FILTER_TYPE = Band Pass
+FILTER_ORDER = 4
+LOW_CUT_FREQUENCY = 1.000000
+HIGH_CUT_FREQUENCY = 20.000000
+
+
+
+########################################################################################################################
+# Stimulation #
+########################################################################################################################
+SCRIPT_TACTILE_STIMULATOR = ${PATH_SCRIPTS}/p300-tactile-stimulator.lua
+N_REPETITIONS = 4
+N_TRIALS = 4
+STIM_DURATION = 0.2
+NO_STIM_DURATION = 0.1
+INTER_REPETITION_DELAY = 1.0
+INTER_TRIAL_DELAY = 4.0
+START_STIMULATION = OVTK_StimulationId_Label_00
+START_DELAY = 20
+
+
+########################################################################################################################
+# Tactilo Control #
+########################################################################################################################
+SERIAL_PORT = /dev/ttyACM0
+
+
+########################################################################################################################
+# Target Generation #
+########################################################################################################################
+SCRIPT_TARGET_GENERATION = ${PATH_SCRIPTS}/p300-tactile-target.lua
+SEND_DELAY = 2
+
+
+########################################################################################################################
+# FILE I/O #
+########################################################################################################################
+OUTPUT_FILE_NAME = ${PATH_SIGNALS}/p300-tactile-session.ov
+INPUT_FILE_NAME = ${PATH_SIGNALS}/p300-tactile-session.ov
+
+
+########################################################################################################################
+# xDAWN Spatial Filter #
+########################################################################################################################
+SPATIAL_TRAIN_TRIGGER = OVTK_StimulationId_ExperimentStop
+SPATIAL_FILTER_CONFIG = ${PATH_CONFIG}/p300-spatial-filter.cfg
+FILTER_DIMENSION = 2
+
+
+########################################################################################################################
+# P300 Classifier #
+########################################################################################################################
+CLASSIFIER_TRAIN_TRIGGER = OVTK_StimulationId_ExperimentStop
+CLASSIFIER_CONFIG = ${PATH_CONFIG}/p300-classifier.cfg
+MULTICLASS_STRATEGY = Native
+CLASS_1 = OVTK_StimulationId_Target
+CLASS_2 = OVTK_StimulationId_NonTarget
+ALGORITHM = Linear Discrimimant Analysis (LDA)
+USE_SHRINKAGE = false
+SHRINKAGE_COEFFICIENT = -1.000000
+SHRINKAGE_FORCE_DIAGONAL_COV = false
+N_PARTITIONS = 5
+CLASS_BALANCE = false
+
+
+########################################################################################################################
+# P300 ACCUMULATOR #
+########################################################################################################################
+SCRIPT_P300_ACCUMULATOR = ${PATH_SCRIPTS}/p300-tactile-accumulator.lua
+
+
+########################################################################################################################
+# Tactile Visualization #
+########################################################################################################################
+TACTILE_UI = ${PATH_UI}/p300-tactile-6.ui
+FLASH_BG = 5,5,5
+FLASH_FG = 100,100,100
+FLASH_FONT_SIZE = 50
+NO_FLASH_BG = 0,0,0
+NO_FLASH_FG = 25,25,25
+NO_FLASH_FONT_SIZE = 50
+TARGET_BG = 20,20,70
+TARGET_FG = 10,10,30
+TARGET_FONT_SIZE = 50
+SELECTED_BG = 10,40,10
+SELECTED_FG = 60,100,60
+SELECTED_FONT_SIZE = 50
+
diff --git a/scenarios/cfg/p300-epoch-average.cfg b/scenarios/cfg/p300-epoch-average.cfg
new file mode 100644
index 0000000..f6b5fdd
--- /dev/null
+++ b/scenarios/cfg/p300-epoch-average.cfg
@@ -0,0 +1,4 @@
+
+ Epoch block average
+ 1
+
diff --git a/scenarios/manuals/Commands_TactileBCI.txt b/scenarios/manuals/Commands_TactileBCI.txt
new file mode 100644
index 0000000..0fc2787
--- /dev/null
+++ b/scenarios/manuals/Commands_TactileBCI.txt
@@ -0,0 +1,58 @@
+#############################################################################################################################################################################################################################################
+# OpenViBE Command Lines Tactile-BCI #
+# #
+# Author : Tobias Baumann #
+# Date : 2022-01-18 #
+#############################################################################################################################################################################################################################################
+
+#############################################################################################################################################################################################################################################
+# Start Acquisition Server #
+#############################################################################################################################################################################################################################################
+
+OV_PATH\openvibe-acquisition-server.cmd --define AcquisitionServer_DefaultDriver DRIVER_NAME --define AcquisitionServer_DefaultSampleCountPerBuffer N_SAMPLES_PER_BUFFER --define AcquisitionServer_DefaultConnectionPort PORT_NUMBER
+
+OV_PATH --> Pfad zur openvibe-acquisition-server.sh
+DRIVER_NAME --> Bezeichnung des zu verwendenden Treibers z.B.: "g.tec Unicorn Gipsa-lab"
+N_SAMPLES_PER_BUFFER --> Anzahl der Samples pro Buffer (4,8,16,32,64,128,256,512) (default: 32)
+PORT_NUMBER --> Vom Acquisition Server verwendeter Port (default: 1024)
+
+
+#############################################################################################################################################################################################################################################
+# Wiedergabe der Szenarios ohne Designer GUI und mit der Konfiguration für das Taktile BCI #
+#############################################################################################################################################################################################################################################
+
+1. Allgemeiner Aufruf:
+
+ OV_PATH\openvibe-designer.cmd --no-gui --config CONFIG_PATH\OV_TACTILE_PANDA.conf --play SCENARIO_PATH\SCENARIO_NAME.xml
+
+ OV_PATH --> Pfad zur openvibe-designer.sh
+ SCENARIO_PATH --> Pfad zu den Szenarios für das Taktile BCI
+ SCENARIO_NAME --> Name des zu startenden Szenarios
+ CONFIG_PATH --> Pfad zur Config für das Taktile BCI (=SCENARIO_PATH\cfg)
+
+2. Szenario 0 - Signal Monitoring:
+
+ OV_PATH\openvibe-designer.sh --no-gui --config CONFIG_PATH\OV_TACTILE_PANDA.conf --play SCENARIO_PATH\p300-tactile-0-signal-monitoring.xml
+
+3. Szenario 1 - Acquisition:
+
+ OV_PATH\openvibe-designer.sh --no-gui --config CONFIG_PATH\OV_TACTILE_PANDA.conf --play SCENARIO_PATH\p300-tactile-1-acquisition.xml
+
+4. Szenario 2 - Train xDAWN Filter:
+
+ OV_PATH\openvibe-designer.sh --no-gui --config CONFIG_PATH\OV_TACTILE_PANDA.conf --playfast SCENARIO_PATH\p300-tactile-2-train-xDAWN.xml
+
+4. Szenario 3 - Train P300 Classifier:
+
+ OV_PATH\openvibe-designer.sh --no-gui --config CONFIG_PATH\OV_TACTILE_PANDA.conf --playfast SCENARIO_PATH\p300-tactile-3-train-classifier.xml
+
+5. Szenario 4 - Online(Free_Spelling):
+
+ OV_PATH\openvibe-designer.sh --no-gui --config CONFIG_PATH\OV_TACTILE_PANDA.conf --define FREE_SPELLING true --play SCENARIO_PATH\p300-tactile-4-online.xml
+
+6. Szenario 4 - Online(Copy_Spelling):
+
+ OV_PATH\openvibe-designer.sh --no-gui --config CONFIG_PATH\OV_TACTILE_PANDA.conf --define FREE_SPELLING false --play SCENARIO_PATH\p300-tactile-4-online.xml
+
+
+
\ No newline at end of file
diff --git a/scenarios/manuals/README.txt b/scenarios/manuals/README.txt
new file mode 100644
index 0000000..e4a9b72
--- /dev/null
+++ b/scenarios/manuals/README.txt
@@ -0,0 +1,7 @@
+p300-tactile:
+
+- Die Szenarien für das Taktile BCI basieren auf dem OpenVibeSzenrio p300-speller-xDAWN.
+- Die Ausführungsreihenfolge ist Acquisition -> train-xDAWN -> train-classifier -> online.
+
+- der Designer muss mit --config CONFIG_PATH\OV_TACTILE_PANDA.conf von der konsole gestartet werden um die im config file festgelegten Tokens verwenden zu können
+- weitere Informationen zum ausführen der Szenarios sind in "Commands_TactileBCI.txt" zu finden
\ No newline at end of file
diff --git a/scenarios/p300-tactile-0-signal-monitoring.xml b/scenarios/p300-tactile-0-signal-monitoring.xml
new file mode 100644
index 0000000..0fe6116
--- /dev/null
+++ b/scenarios/p300-tactile-0-signal-monitoring.xml
@@ -0,0 +1,743 @@
+
+ 2
+ OpenViBE Designer
+ 3.3.0
+
+
+
+
+
+ (0x000014bf, 0x000034db)
+ Identity
+ (0x5dffe431, 0x35215c50)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input stream 1
+
+
+ (0x5ba36127, 0x195feae1)
+ Input stream 2
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stream 3
+
+
+
+
+
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 432
+
+
+ (0x207c9054, 0x3c841b63)
+ 928
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xa8ffe2a3, 0x27038f03)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xac367a9c, 0x2da95abe)
+ 6
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00003f1b, 0x00003c78)
+ Signal Decimation
+ (0x012f4bea, 0x3be37c66)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Decimation factor
+ 8
+ ${SIGNAL_DECIMATION_FACTOR}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 336
+
+
+ (0x207c9054, 0x3c841b63)
+ 816
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x5082af41, 0xd0fbf4cb)
+
+
+
+
+ (0x000046bc, 0x00003f08)
+ Temporal Filter
+ (0xb4f9d042, 0x9d79f2e5)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0xfa20178e, 0x4cba62e9)
+ Filter Type
+ Band Pass
+ ${FILTER_TYPE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Filter Order
+ 4
+ ${FILTER_ORDER}
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Low Cut-off Frequency (Hz)
+ 1
+ ${LOW_CUT_FREQUENCY}
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ High Cut-off Frequency (Hz)
+ 40
+ ${HIGH_CUT_FREQUENCY}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 256
+
+
+ (0x207c9054, 0x3c841b63)
+ 816
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x6a7c1e9b, 0x6b00b5c5)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 4
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x00005c5c, 0x00007610)
+ Raw
+ (0x0055be5f, 0x087bdd12)
+
+
+ (0x5ba36127, 0x195feae1)
+ Data
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+ (0x6ab26b81, 0x0f8c02f3)
+ Channel Units
+
+
+
+
+ (0x5de046a6, 0x086340aa)
+ Display Mode
+ Scan
+ Scan
+ false
+
+
+ (0x33a30739, 0x00d5299b)
+ Auto vertical scale
+ Per channel
+ Per channel
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Scale refresh interval (secs)
+ 5
+ 0.000000
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Scale
+ 100
+ 100
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Offset
+ 0
+ 0
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Time Scale
+ 10
+ 5.000000
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Horizontal ruler
+ true
+ true
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Vertical ruler
+ false
+ false
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Multiview
+ false
+ false
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 560
+
+
+ (0x207c9054, 0x3c841b63)
+ 1024
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x92c056a7, 0x2dc71aff)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xce18836a, 0x9c0eb403)
+ 9
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 3
+
+
+
+
+ (0x00006b6d, 0x00002690)
+ Acquisition client
+ (0x35d225cb, 0x3e6e3a5f)
+
+
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Acquisition server hostname
+ ${AcquisitionServer_HostName}
+ ${ACQUISITION_SERVER_HOST_NAME}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Acquisition server port
+ 1024
+ ${ACQUISITION_SERVER_PORT}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 64
+
+
+ (0x207c9054, 0x3c841b63)
+ 944
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x0d4656c0, 0xc95b1fa8)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xc80ce8af, 0xf699f813)
+ 5
+
+
+ (0xce18836a, 0x9c0eb403)
+ 2
+
+
+
+
+ (0x00007e4e, 0x00006b7b)
+ Filtered
+ (0x0055be5f, 0x087bdd12)
+
+
+ (0x5ba36127, 0x195feae1)
+ Data
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+ (0x6ab26b81, 0x0f8c02f3)
+ Channel Units
+
+
+
+
+ (0x5de046a6, 0x086340aa)
+ Display Mode
+ Scan
+ Scan
+ false
+
+
+ (0x33a30739, 0x00d5299b)
+ Auto vertical scale
+ Per channel
+ Per channel
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Scale refresh interval (secs)
+ 5
+ 0.000000
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Scale
+ 100
+ 100
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Offset
+ 0
+ 0
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Time Scale
+ 10
+ 5.000000
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Horizontal ruler
+ true
+ true
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Vertical ruler
+ false
+ false
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Multiview
+ false
+ false
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 560
+
+
+ (0x207c9054, 0x3c841b63)
+ 832
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x92c056a7, 0x2dc71aff)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xce18836a, 0x9c0eb403)
+ 9
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 3
+
+
+
+
+ (0x4ff47ca1, 0x133bd33b)
+ EEG Signal Selection
+ (0x361722e8, 0x311574e8)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Channel List
+ :
+ ${CHANNEL_SELECTION}
+ false
+
+
+ (0x3bcf9e67, 0x0c23994d)
+ Action
+ Select
+ Select
+ false
+
+
+ (0x666f25e9, 0x3e5738d6)
+ Channel Matching Method
+ Smart
+ Index
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 176
+
+
+ (0x207c9054, 0x3c841b63)
+ 864
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x277826e1, 0xa30a3bd0)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+
+
+ (0x000003a7, 0x000034db)
+
+ (0x000014bf, 0x000034db)
+ 2
+
+
+ (0x00005c5c, 0x00007610)
+ 1
+
+
+
+ (0x00000554, 0x0000661a)
+
+ (0x000014bf, 0x000034db)
+ 2
+
+
+ (0x00007e4e, 0x00006b7b)
+ 1
+
+
+
+ (0x00001d33, 0x00002bb0)
+
+ (0x00006b6d, 0x00002690)
+ 2
+
+
+ (0x000014bf, 0x000034db)
+ 2
+
+
+
+ (0x00003f04, 0x000045c3)
+
+ (0x000014bf, 0x000034db)
+ 1
+
+
+ (0x00005c5c, 0x00007610)
+ 0
+
+
+
+ (0x00004b11, 0x00006a43)
+
+ (0x00003f1b, 0x00003c78)
+ 0
+
+
+ (0x000014bf, 0x000034db)
+ 0
+
+
+
+ (0x000056fd, 0x00004795)
+
+ (0x000014bf, 0x000034db)
+ 0
+
+
+ (0x00007e4e, 0x00006b7b)
+ 0
+
+
+
+ (0x2336eb7d, 0x44803e51)
+
+ (0x4ff47ca1, 0x133bd33b)
+ 0
+
+
+ (0x000046bc, 0x00003f08)
+ 0
+
+
+
+ (0x384b6f31, 0x639fff7d)
+
+ (0x4ff47ca1, 0x133bd33b)
+ 0
+
+
+ (0x000014bf, 0x000034db)
+ 1
+
+
+
+ (0x771fd1ca, 0x72794515)
+
+ (0x000046bc, 0x00003f08)
+ 0
+
+
+ (0x00003f1b, 0x00003c78)
+ 0
+
+
+
+ (0x7c0285ed, 0x7aaf8bb7)
+
+ (0x00006b6d, 0x00002690)
+ 1
+
+
+ (0x4ff47ca1, 0x133bd33b)
+ 0
+
+
+
+
+
+ (0x000028e8, 0x00003dee)
+ <u><b><big>Scenario Overview</big></b></u>
+
+This scenario can be used in order
+to check the quality of the signals
+before starting an experiment.
+
+One should <u>definitely</u>
+check the quality of the signals
+and ensure that :
+
+- <b>eye blinks</b> are visible
+- <b>jaw clenching</b> are visible
+- <b>alpha waves</b> are visible when closing eyes
+
+Two Signals are displayed, one is the raw EEG-Signal
+and the other one is the filtered signal.
+The filtered signal is the one, that will actually be used
+in other scenarios.
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 576
+
+
+ (0x7234b86b, 0x2b8651a5)
+ 272
+
+
+
+
+
+
+ (0x0000775c, 0x000078ff)
+ (0x3bcce5d2, 0x43f2d968)
+ [{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":635,"identifier":"(0x000077ee, 0x0000254d)","name":"default","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":783},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00004579, 0x00005fcb)","index":0,"name":"Default tab","parentIdentifier":"(0x000077ee, 0x0000254d)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":2,"dividerPosition":293,"identifier":"(0x00005446, 0x000043a1)","index":0,"maxDividerPosition":590,"name":"Vertical split","parentIdentifier":"(0x00004579, 0x00005fcb)","type":4},{"boxIdentifier":"(0x00005c5c, 0x00007610)","childCount":0,"identifier":"(0x00000e42, 0x000074b8)","index":0,"parentIdentifier":"(0x00005446, 0x000043a1)","type":3},{"boxIdentifier":"(0x00007e4e, 0x00006b7b)","childCount":0,"identifier":"(0x00005db7, 0x000032ad)","index":1,"parentIdentifier":"(0x00005446, 0x000043a1)","type":3}]
+
+
+
+
+ (0x790d75b8, 0x3bb90c33)
+ Yann Renard
+
+
+ (0x8c1fc55b, 0x7b433dc2)
+
+
+
+ (0x9f5c4075, 0x4a0d3666)
+ Signal Monitoring
+
+
+ (0xf36a1567, 0xd13c53da)
+ http://openvibe.inria.fr/p300-speller-xdawn/
+
+
+ (0xf6b2e3fa, 0x7bd43926)
+ xDAWN P300 Speller
+
+
+ (0xf8034a49, 0x8b3f37cc)
+ INRIA
+
+
+
\ No newline at end of file
diff --git a/scenarios/p300-tactile-1-acquisition.xml b/scenarios/p300-tactile-1-acquisition.xml
new file mode 100644
index 0000000..f6ecde8
--- /dev/null
+++ b/scenarios/p300-tactile-1-acquisition.xml
@@ -0,0 +1,1210 @@
+
+ 2
+ OpenViBE Designer
+ 3.3.0
+
+
+
+
+
+ (0x0000356c, 0x00004381)
+ Generic stream writer
+ (0x09c92218, 0x7c1216f8)
+
+
+ (0x403488e7, 0x565d70b6)
+ Input stream 1
+
+
+ (0x5ba36127, 0x195feae1)
+ Input stream 2
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stream 3
+
+
+
+
+ (0x330306dd, 0x74a95f98)
+ Filename
+
+ ${OUTPUT_FILE_NAME}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Use compression
+ false
+ false
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 832
+
+
+ (0x207c9054, 0x3c841b63)
+ 576
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x89a08108, 0xc8d1fac1)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x0350a9f0)
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00003f1b, 0x00003c78)
+ Signal Decimation
+ (0x012f4bea, 0x3be37c66)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Decimation factor
+ 8
+ ${SIGNAL_DECIMATION_FACTOR}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 688
+
+
+ (0x207c9054, 0x3c841b63)
+ 544
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x5082af41, 0xd0fbf4cb)
+
+
+
+
+ (0x000046bc, 0x00003f08)
+ Temporal Filter
+ (0xb4f9d042, 0x9d79f2e5)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0xfa20178e, 0x4cba62e9)
+ Filter Type
+ Band Pass
+ ${FILTER_TYPE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Filter Order
+ 4
+ ${FILTER_ORDER}
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Low Cut-off Frequency (Hz)
+ 1
+ ${LOW_CUT_FREQUENCY}
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ High Cut-off Frequency (Hz)
+ 40
+ ${HIGH_CUT_FREQUENCY}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 640
+
+
+ (0x207c9054, 0x3c841b63)
+ 544
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x6a7c1e9b, 0x6b00b5c5)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 4
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x0000470b, 0x00001b1d)
+ Tactile Stimulator
+ (0x0b5a2787, 0x02750621)
+
+
+
+
+
+ (0xb0d0db45, 0x49cbc34a)
+ Lua Script
+
+ ${SCRIPT_TACTILE_STIMULATOR}
+ false
+
+
+ (0x00000000, 0xbae13066)
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x00000000, 0xc152613d)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+ (0x00000000, 0xa0308929)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Repetitions
+ 6
+ ${N_REPETITIONS}
+ false
+
+
+ (0x00000000, 0xcde95a6f)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Trials
+ 6
+ ${N_TRIALS}
+ false
+
+
+ (0x00000000, 0x9b3f9b7b)
+ (0x512a166f, 0x5c3ef83f)
+ Stimulus Duration (in sec)
+ 0.2
+ ${STIM_DURATION}
+ false
+
+
+ (0x00000000, 0x583ad367)
+ (0x512a166f, 0x5c3ef83f)
+ No Stimulus Duration (in sec)
+ 0.1
+ ${NO_STIM_DURATION}
+ false
+
+
+ (0x00000000, 0xfc1c2fb6)
+ (0x512a166f, 0x5c3ef83f)
+ Inter-Repetition Delay (in sec)
+ 1.0
+ ${INTER_REPETITION_DELAY}
+ false
+
+
+ (0x00000000, 0x0d9a1e18)
+ (0x512a166f, 0x5c3ef83f)
+ Inter-Trial Delay (in sec)
+ 3.0
+ ${INTER_TRIAL_DELAY}
+ false
+
+
+ (0x00000000, 0xaeefd500)
+ (0x2c132d6e, 0x44ab0d97)
+ Start Stimulation
+ OVTK_StimulationId_Label_00
+ ${START_STIMULATION}
+ false
+
+
+ (0x00000000, 0xef5eb0e5)
+ (0x2cdb2f0b, 0x12f231ea)
+ Free Spelling
+ false
+ false
+ false
+
+
+ (0x00000000, 0x4ead155d)
+ (0x007deef9, 0x2f3e95c6)
+ Start Delay
+ 20
+ ${START_DELAY}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 160
+
+
+ (0x207c9054, 0x3c841b63)
+ 624
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xd6e3f48b, 0xbee3523a)
+
+
+ (0x61d11811, 0x71e65362)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 1
+
+
+ (0xf191c1c8, 0xa0123976)
+
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00004eca, 0x00003f33)
+ Player Controller
+ (0x5f426dce, 0x08456e13)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation name
+ OVTK_StimulationId_Label_00
+ OVTK_StimulationId_ExperimentStop
+ false
+
+
+ (0xcc14d8d6, 0xf27ecb73)
+ Action to perform
+ Pause
+ Stop
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 624
+
+
+ (0x207c9054, 0x3c841b63)
+ 720
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x568d148e, 0x650792b3)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x01070ba6)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xce18836a, 0x9c0eb403)
+ 2
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x0000599b, 0x000026ba)
+ Acquisition client
+ (0x35d225cb, 0x3e6e3a5f)
+
+
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Acquisition server hostname
+ ${AcquisitionServer_HostName}
+ ${ACQUISITION_SERVER_HOST_NAME}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Acquisition server port
+ 1024
+ ${ACQUISITION_SERVER_PORT}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 480
+
+
+ (0x207c9054, 0x3c841b63)
+ 624
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x0d4656c0, 0xc95b1fa8)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x02909b75)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xc80ce8af, 0xf699f813)
+ 5
+
+
+ (0xce18836a, 0x9c0eb403)
+ 2
+
+
+
+
+ (0x00006d0d, 0x000031da)
+ Tactile Target Generation
+ (0x0b5a2787, 0x02750621)
+
+
+ (0x6f752dd0, 0x082a321e)
+ New input
+
+
+
+
+
+
+
+ (0xb0d0db45, 0x49cbc34a)
+ Lua Script
+
+ ${SCRIPT_TARGET_GENERATION}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x00000000, 0xeb4fffa2)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+ (0xf33dddda, 0xfd2c04a3)
+ (0x007deef9, 0x2f3e95c6)
+ Delay Before Sending (in sec)
+ 2
+ ${SEND_DELAY}
+ false
+
+
+ (0xa95b0b1d, 0x12aa8207)
+ (0x2cdb2f0b, 0x12f231ea)
+ Free Spelling
+ false
+ false
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 288
+
+
+ (0x207c9054, 0x3c841b63)
+ 720
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xd6e3f48b, 0xbee3523a)
+
+
+ (0x61d11811, 0x71e65362)
+
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x0334c6b7)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 1
+
+
+ (0xf191c1c8, 0xa0123976)
+
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00007e4e, 0x00006b7c)
+ EEG Signal
+ (0x0055be5f, 0x087bdd12)
+
+
+ (0x5ba36127, 0x195feae1)
+ Data
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+ (0x6ab26b81, 0x0f8c02f3)
+ Channel Units
+
+
+
+
+ (0x5de046a6, 0x086340aa)
+ Display Mode
+ Scan
+ Scan
+ false
+
+
+ (0x33a30739, 0x00d5299b)
+ Auto vertical scale
+ Per channel
+ Per channel
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Scale refresh interval (secs)
+ 5
+ 0.000000
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Scale
+ 100
+ 100
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Offset
+ 0
+ 0
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Time Scale
+ 10
+ 5.000000
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Horizontal ruler
+ true
+ true
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Vertical ruler
+ false
+ false
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Multiview
+ false
+ false
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 832
+
+
+ (0x207c9054, 0x3c841b63)
+ 704
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x92c056a7, 0x2dc71aff)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xce18836a, 0x9c0eb403)
+ 9
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 3
+
+
+
+
+ (0x2ae25693, 0x5aacdae0)
+ P300TactileVisualization
+ (0xd463df86, 0x7fbfdd81)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Sequence
+
+
+ (0x6f752dd0, 0x082a321e)
+ Target
+
+
+ (0x6f752dd0, 0x082a321e)
+ Result
+
+
+
+
+
+
+
+ (0x330306dd, 0x74a95f98)
+ Interface Filename
+ /ui/p300-tactile-6.ui
+ ${TACTILE_UI}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Free Spelling
+ false
+ false
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 400
+
+
+ (0x207c9054, 0x3c841b63)
+ 608
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x4b4912a1, 0xc1409d95)
+
+
+ (0x666fffff, 0x666fffff)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 4
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 3
+
+
+
+
+ (0x4ade5889, 0x17459601)
+ Identity
+ (0x5dffe431, 0x35215c50)
+
+
+ (0x5ba36127, 0x195feae1)
+ EEG Signal
+
+
+ (0x637728e4, 0xba606dd1)
+ (0x6f752dd0, 0x082a321e)
+ Stimulation
+
+
+
+
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 736
+
+
+ (0x207c9054, 0x3c841b63)
+ 624
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xa8ffe2a3, 0x27038f03)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x4ff47ca1, 0x133bd33c)
+ EEG Channel Selection
+ (0x361722e8, 0x311574e8)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Channel List
+ :
+ ${CHANNEL_SELECTION}
+ false
+
+
+ (0x3bcf9e67, 0x0c23994d)
+ Action
+ Select
+ Select
+ false
+
+
+ (0x666f25e9, 0x3e5738d6)
+ Channel Matching Method
+ Smart
+ Index
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 576
+
+
+ (0x207c9054, 0x3c841b63)
+ 544
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x277826e1, 0xa30a3bd0)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x75c23c9b, 0x31b0f712)
+ Tactilo Controller
+ (0x823bbe28, 0x0daf2111)
+
+
+ (0x6f752dd0, 0x082a321e)
+ StimInput
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Serial Port Name
+ /dev/ttyACM0
+ ${SERIAL_PORT}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 288
+
+
+ (0x207c9054, 0x3c841b63)
+ 560
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xa638e513, 0x9a753d4b)
+
+
+ (0x666fffff, 0x666fffff)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+
+
+ (0x00001e35, 0x00003016)
+
+ (0x0000599b, 0x000026ba)
+ 2
+
+
+ (0x00004eca, 0x00003f33)
+ 0
+
+
+
+ (0x000048ba, 0x0000793e)
+
+ (0x0000470b, 0x00001b1d)
+ 0
+
+
+ (0x00006d0d, 0x000031da)
+ 0
+
+
+
+ (0x1a70f30d, 0x50647e8c)
+
+ (0x0000470b, 0x00001b1d)
+ 0
+
+
+ (0x75c23c9b, 0x31b0f712)
+ 0
+
+
+
+ (0x27893ae2, 0x55f4a507)
+
+ (0x00003f1b, 0x00003c78)
+ 0
+
+
+ (0x4ade5889, 0x17459601)
+ 0
+
+
+
+ (0x2a77405b, 0x472854cc)
+
+ (0x000046bc, 0x00003f08)
+ 0
+
+
+ (0x00003f1b, 0x00003c78)
+ 0
+
+
+
+ (0x2c26a8b6, 0x6188bc2d)
+
+ (0x4ade5889, 0x17459601)
+ (0x4634ca30, 0x4eba507b)
+
+
+ (0x0000356c, 0x00004381)
+ 2
+
+
+
+ (0x3071bbd6, 0x1170b46f)
+
+ (0x75c23c9b, 0x31b0f712)
+ 0
+
+
+ (0x2ae25693, 0x5aacdae0)
+ 0
+
+
+
+ (0x39f52e7c, 0x285a7107)
+
+ (0x0000599b, 0x000026ba)
+ 1
+
+
+ (0x4ff47ca1, 0x133bd33c)
+ 0
+
+
+
+ (0x478989f0, 0x1b494dfc)
+
+ (0x00006d0d, 0x000031da)
+ 0
+
+
+ (0x2ae25693, 0x5aacdae0)
+ 1
+
+
+
+ (0x4d4cba8a, 0x5cbf79c7)
+
+ (0x4ade5889, 0x17459601)
+ 0
+
+
+ (0x00007e4e, 0x00006b7c)
+ 0
+
+
+
+ (0x5d9ef0f2, 0x40736918)
+
+ (0x4ff47ca1, 0x133bd33c)
+ 0
+
+
+ (0x000046bc, 0x00003f08)
+ 0
+
+
+
+ (0x6552e5c0, 0x2866044c)
+
+ (0x0000599b, 0x000026ba)
+ 2
+
+
+ (0x4ade5889, 0x17459601)
+ (0x637728e4, 0xba606dd1)
+
+
+
+ (0x6eb8c286, 0x24e6b63f)
+
+ (0x4ade5889, 0x17459601)
+ (0x4634ca30, 0x4eba507b)
+
+
+ (0x00007e4e, 0x00006b7c)
+ 1
+
+
+
+ (0x70d4fe7b, 0x57913744)
+
+ (0x4ade5889, 0x17459601)
+ 0
+
+
+ (0x0000356c, 0x00004381)
+ 1
+
+
+
+
+
+ (0x0000363f, 0x00001c2b)
+ The P300 Speller Visualization
+sends the markers (stimulations) directly to
+Acquisition Server using TCP Tagging.
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 864
+
+
+ (0x7234b86b, 0x2b8651a5)
+ 400
+
+
+
+
+ (0x19b8795c, 0x039f26f7)
+ <u><b><big>Scenario Overview</big></b></u>
+
+This scenario is used as a first step to
+collect some training data. The data
+will later be used to train a spatial
+filter and a classifier for online use of
+the Tactile BCI System.
+
+Spelling automatically starts delayed to the start
+of scenario execution.
+
+First the target Tactilo will vibrate and flash in the
+<i>Speller Visualization</i>(Copy Spelling Only).
+After that you have to Focus on your chosen
+(or the predetermined Target), while all Tactilos
+will vibrate (flash) several times.
+This will be repeated for a defined number of trials.
+After each Trial, the detected Tactilo will be presented
+in the <i>Speller Visualization</i>
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 320
+
+
+ (0x7234b86b, 0x2b8651a5)
+ 288
+
+
+
+
+
+
+ (0x0000775c, 0x000078ff)
+ (0x3bcce5d2, 0x43f2d968)
+ [{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":2,"height":320,"identifier":"(0x00003bb5, 0x00006280)","name":"Acquisition","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":477},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x0000339c, 0x00002646)","index":0,"name":"Tactile Visualization","parentIdentifier":"(0x00003bb5, 0x00006280)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00003667, 0x00007632)","index":1,"name":"EEG Signal","parentIdentifier":"(0x00003bb5, 0x00006280)","type":2},{"boxIdentifier":"(0x2ae25693, 0x5aacdae0)","childCount":0,"identifier":"(0x2859de2f, 0x369b7e62)","index":0,"parentIdentifier":"(0x0000339c, 0x00002646)","type":3},{"boxIdentifier":"(0x00007e4e, 0x00006b7c)","childCount":0,"identifier":"(0x00004ac1, 0x000015aa)","index":0,"parentIdentifier":"(0x00003667, 0x00007632)","type":3}]
+
+
+
+
+ (0x790d75b8, 0x3bb90c33)
+ Yann Renard, Jussi T. Lindgren
+
+
+ (0x8c1fc55b, 0x7b433dc2)
+
+
+
+ (0x9f5c4075, 0x4a0d3666)
+ Data Acquisition
+
+
+ (0xf36a1567, 0xd13c53da)
+ http://openvibe.inria.fr/p300-speller-xdawn/
+
+
+ (0xf6b2e3fa, 0x7bd43926)
+ xDAWN P300 Speller
+
+
+ (0xf8034a49, 0x8b3f37cc)
+ INRIA
+
+
+
\ No newline at end of file
diff --git a/scenarios/p300-tactile-2-train-xDAWN.xml b/scenarios/p300-tactile-2-train-xDAWN.xml
new file mode 100644
index 0000000..445a9e4
--- /dev/null
+++ b/scenarios/p300-tactile-2-train-xDAWN.xml
@@ -0,0 +1,438 @@
+
+ 2
+ OpenViBE Designer
+ 3.3.0
+
+
+
+
+
+ (0x00001db8, 0x00001848)
+ xDAWN Trainer
+ (0x27542f6e, 0x14aa3548)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+ (0x5ba36127, 0x195feae1)
+ Session signal
+
+
+ (0x5ba36127, 0x195feae1)
+ Evoked potential epochs
+
+
+
+
+
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Train stimulation
+ OVTK_StimulationId_Train
+ ${SPATIAL_TRAIN_TRIGGER}
+ false
+
+
+ (0x330306dd, 0x74a95f98)
+ Spatial filter configuration
+
+ ${SPATIAL_FILTER_CONFIG}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Filter dimension
+ 4
+ ${FILTER_DIMENSION}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Save as box config
+ true
+ true
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 176
+
+
+ (0x207c9054, 0x3c841b63)
+ 288
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x4b49a133, 0x42f38d94)
+
+
+ (0xc80ce8af, 0xf699f813)
+
+
+
+ (0xce18836a, 0x9c0eb403)
+
+
+
+ (0xcfad85b0, 0x7c6d841c)
+
+
+
+
+
+ (0x00002514, 0x00001614)
+ Generic stream reader
+ (0x6468099f, 0x0370095a)
+
+
+
+
+
+
+
+ (0x330306dd, 0x74a95f98)
+ Filename
+
+ ${INPUT_FILE_NAME}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ -128
+
+
+ (0x207c9054, 0x3c841b63)
+ 400
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xf37b8e7a, 0x1bc33e4e)
+
+
+
+
+ (0x0000267a, 0x0000427f)
+ Time based epoching
+ (0x00777fa0, 0x5dc3f560)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch 1 duration (in sec)
+ 1
+ 0.250000
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch 1 intervals (in sec)
+ 0.5
+ 0.250000
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ -16
+
+
+ (0x207c9054, 0x3c841b63)
+ 288
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xc5ff41e9, 0xccc59a01)
+
+
+
+
+ (0x00004aea, 0x00001465)
+ Player Controller
+ (0x5f426dce, 0x08456e13)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation name
+ OVTK_StimulationId_Label_00
+ OVTK_StimulationId_TrainCompleted
+ false
+
+
+ (0xcc14d8d6, 0xf27ecb73)
+ Action to perform
+ Pause
+ Stop
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 240
+
+
+ (0x207c9054, 0x3c841b63)
+ 288
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x568d148e, 0x650792b3)
+
+
+ (0xce18836a, 0x9c0eb403)
+ 2
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x00006fa4, 0x00003c77)
+ Target Selection
+ (0x426163d1, 0x324237b0)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stimulations
+
+
+
+
+
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch duration (in sec)
+ 1
+ 0.6
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch offset (in sec)
+ 0.5
+ 0
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation to epoch from
+ OVTK_GDF_VEP
+ OVTK_StimulationId_Target
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 64
+
+
+ (0x207c9054, 0x3c841b63)
+ 416
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x5de31172, 0xa1304456)
+
+
+
+
+
+
+ (0x00003920, 0x00007a30)
+
+ (0x0000267a, 0x0000427f)
+ 0
+
+
+ (0x00001db8, 0x00001848)
+ 1
+
+
+
+ (0x00004bf5, 0x00007908)
+
+ (0x00001db8, 0x00001848)
+ 0
+
+
+ (0x00004aea, 0x00001465)
+ 0
+
+
+
+ (0x000059e8, 0x00000032)
+
+ (0x00002514, 0x00001614)
+ 2
+
+
+ (0x00001db8, 0x00001848)
+ 0
+
+
+
+ (0x00006913, 0x00003182)
+
+ (0x00002514, 0x00001614)
+ 1
+
+
+ (0x0000267a, 0x0000427f)
+ 0
+
+
+
+ (0x074b170c, 0x37e84571)
+
+ (0x0000267a, 0x0000427f)
+ 0
+
+
+ (0x00006fa4, 0x00003c77)
+ 0
+
+
+
+ (0x188f2058, 0x7ac23f09)
+
+ (0x00006fa4, 0x00003c77)
+ 0
+
+
+ (0x00001db8, 0x00001848)
+ 2
+
+
+
+ (0x2b245a90, 0x47f6e438)
+
+ (0x00002514, 0x00001614)
+ 2
+
+
+ (0x00006fa4, 0x00003c77)
+ 1
+
+
+
+
+
+ (0x000049d6, 0x00006e67)
+ <u><b><big>Scenario Overview</big></b></u>
+
+This scenario should be used to train
+the spatial filter using the xDAWN algorithm.
+
+At the end of the training, you will have line in
+the console about eigen values.
+Using a <i>Player Controller</i> the scenario will
+automatically pause at the end of the training.
+
+If you want details on this values, you should read
+<u>http://www.icp.inpg.fr/~rivetber/Publications/references/Rivet2009a.pdf</u>
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 704
+
+
+ (0x7234b86b, 0x2b8651a5)
+ -32
+
+
+
+
+
+
+ (0x0000775c, 0x000078ff)
+ (0x3bcce5d2, 0x43f2d968)
+ []
+
+
+
+
+ (0x790d75b8, 0x3bb90c33)
+ Yann Renard
+
+
+ (0x8c1fc55b, 0x7b433dc2)
+
+
+
+ (0x9f5c4075, 0x4a0d3666)
+ Spatial Filter Training
+
+
+ (0xf36a1567, 0xd13c53da)
+ http://openvibe.inria.fr/p300-speller-xdawn/
+
+
+ (0xf6b2e3fa, 0x7bd43926)
+ xDAWN P300 Speller
+
+
+ (0xf8034a49, 0x8b3f37cc)
+ INRIA
+
+
+
\ No newline at end of file
diff --git a/scenarios/p300-tactile-3-train-classifier.xml b/scenarios/p300-tactile-3-train-classifier.xml
new file mode 100644
index 0000000..00b22e9
--- /dev/null
+++ b/scenarios/p300-tactile-3-train-classifier.xml
@@ -0,0 +1,898 @@
+
+ 2
+ OpenViBE Designer
+ 3.3.0
+
+
+
+
+
+ (0x00000b2d, 0x00006d61)
+ Feature aggregator
+ (0x00682417, 0x453635f9)
+
+
+ (0x544a003e, 0x6dcba5f6)
+ Input stream 1
+
+
+
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 240
+
+
+ (0x207c9054, 0x3c841b63)
+ 336
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xb5d15cc9, 0x6c8c28fb)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002bb807)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00000d41, 0x000013b7)
+ Feature aggregator
+ (0x00682417, 0x453635f9)
+
+
+ (0x544a003e, 0x6dcba5f6)
+ Input stream 1
+
+
+
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 240
+
+
+ (0x207c9054, 0x3c841b63)
+ 528
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xb5d15cc9, 0x6c8c28fb)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002b7d6e)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00001f83, 0x00004e32)
+ Generic stream reader
+ (0x6468099f, 0x0370095a)
+
+
+
+
+
+
+
+ (0x330306dd, 0x74a95f98)
+ Filename
+
+ ${INPUT_FILE_NAME}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ -160
+
+
+ (0x207c9054, 0x3c841b63)
+ 400
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xf37b8e7a, 0x1bc33e4e)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x008e34c7)
+
+
+
+
+ (0x00002c8b, 0x000001d5)
+ Player Controller
+ (0x5f426dce, 0x08456e13)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation name
+ OVTK_StimulationId_Label_00
+ OVTK_StimulationId_TrainCompleted
+ false
+
+
+ (0xcc14d8d6, 0xf27ecb73)
+ Action to perform
+ Pause
+ Stop
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 416
+
+
+ (0x207c9054, 0x3c841b63)
+ 448
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x568d148e, 0x650792b3)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x00301c7f)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xce18836a, 0x9c0eb403)
+ 2
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x00002f94, 0x00000342)
+ Non Target Selection
+ (0x426163d1, 0x324237b0)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stimulations
+
+
+
+
+
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch duration (in sec)
+ 1
+ 0.6
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch offset (in sec)
+ 0.5
+ 0
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation to epoch from
+ OVTK_GDF_VEP
+ OVTK_StimulationId_NonTarget
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 112
+
+
+ (0x207c9054, 0x3c841b63)
+ 528
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x5de31172, 0xa1304456)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002bbddf)
+
+
+
+
+ (0x000063a5, 0x0000197d)
+ Target Selection
+ (0x426163d1, 0x324237b0)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stimulations
+
+
+
+
+
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch duration (in sec)
+ 1
+ 0.6
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch offset (in sec)
+ 0.5
+ 0
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation to epoch from
+ OVTK_GDF_VEP
+ OVTK_StimulationId_Target
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 112
+
+
+ (0x207c9054, 0x3c841b63)
+ 336
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x5de31172, 0xa1304456)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002b4e91)
+
+
+
+
+ (0x000078d0, 0x000029bc)
+ Epoch average
+ (0x21283d9f, 0xe76ff640)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input epochs
+
+
+
+
+
+
+
+ (0x6530bdb1, 0xd057bbfe)
+ Averaging type
+ Epoch block average
+ Epoch block average
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Epoch count
+ 4
+ 1
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 176
+
+
+ (0x207c9054, 0x3c841b63)
+ 336
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xb73cee83, 0xf7215d60)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0x8d21ff41, 0xdf6afe7e)
+ ${Player_ScenarioDirectory}/cfg/p300-epoch-average.cfg
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002b5470)
+
+
+
+
+ (0x000078f9, 0x000063eb)
+ xDAWN Spatial Filter
+ (0xdd332c6c, 0x195b4fd4)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input Signal
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Spatial Filter Coefficients
+ 1;0;0;0;0;1;0;0;0;0;1;0;0;0;0;1
+ 9.970221e-001 -3.729500e-002 -1.177390e-002 2.814447e-002 -3.772446e-003 3.371324e-002 -5.480030e-003 8.893039e-003 -1.565213e-002 -9.956694e-003 -2.347757e-002 -2.312669e-003 -1.847227e-002 -7.550644e-004 -8.423513e-003 3.243223e-002 2.079848e-002 5.079737e-001 -2.835127e-002 8.259231e-002 -3.621803e-001 -2.004259e-001 -2.432480e-001 -1.861558e-001 -3.798139e-001 9.614762e-002 3.407766e-001 -2.158597e-001 3.720552e-001 7.500469e-002 -8.628774e-002 -3.182367e-002 5.923482e-002 4.124707e-001 2.083913e-001 -2.629501e-001 2.023081e-001 -2.658446e-001 4.022738e-001 -1.785569e-001 4.450742e-001 3.549239e-001 1.550204e-002 3.750389e-002 3.114249e-002 9.273764e-002 -7.093797e-002 -2.610929e-001
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Output Channels
+ 4
+ 3
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Input Channels
+ 4
+ 16
+ false
+
+
+ (0x330306dd, 0x74a95f98)
+ Filter matrix file
+
+
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ -32
+
+
+ (0x207c9054, 0x3c841b63)
+ 304
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x81db9bf9, 0xf1cf4ed7)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0x8d21ff41, 0xdf6afe7e)
+ ${SPATIAL_FILTER_CONFIG}
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002b601f)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x00007b56, 0x000033f9)
+ Epoch average
+ (0x21283d9f, 0xe76ff640)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input epochs
+
+
+
+
+
+
+
+ (0x6530bdb1, 0xd057bbfe)
+ Averaging type
+ Epoch block average
+ Epoch block average
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Epoch count
+ 4
+ 1
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 176
+
+
+ (0x207c9054, 0x3c841b63)
+ 528
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xb73cee83, 0xf7215d60)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0x8d21ff41, 0xdf6afe7e)
+ ${Player_ScenarioDirectory}/cfg/p300-epoch-average.cfg
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002c2168)
+
+
+
+
+ (0x0a5a6a4a, 0x1d92a778)
+ Classifier trainer
+ (0xf3dae8a8, 0x3b444154)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+ (0x17341935, 0x152ff448)
+ Features for class 1
+
+
+ (0x17341935, 0x152ff448)
+ Features for class 2
+
+
+
+
+
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Train trigger
+ OVTK_StimulationId_Train
+ ${CLASSIFIER_TRAIN_TRIGGER}
+ false
+
+
+ (0x330306dd, 0x74a95f98)
+ Filename to save configuration to
+ ${Path_UserData}/my-classifier.xml
+ ${CLASSIFIER_CONFIG}
+ false
+
+
+ (0xbe9eba5c, 0xa8415d37)
+ Multiclass strategy to apply
+ Native
+ ${MULTICLASS_STRATEGY}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Class 1 label
+ OVTK_StimulationId_Label_01
+ ${CLASS_1}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Class 2 label
+ OVTK_StimulationId_Label_02
+ ${CLASS_2}
+ false
+
+
+ (0xd765a736, 0xed708c65)
+ Algorithm to use
+ Linear Discrimimant Analysis (LDA)
+ ${ALGORITHM}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Use shrinkage
+ false
+ ${USE_SHRINKAGE}
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Shrinkage coefficient (-1 == auto)
+ -1.000000
+ ${SHRINKAGE_COEFFICIENT}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Shrinkage: Force diagonal cov (DDA)
+ false
+ ${SHRINKAGE_FORCE_DIAGONAL_COV}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of partitions for k-fold cross-validation test
+ 10
+ ${N_PARTITIONS}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Balance classes
+ false
+ ${CLASS_BALANCE}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 336
+
+
+ (0x207c9054, 0x3c841b63)
+ 448
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x9de21779, 0x37776c89)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 6
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 3
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+
+
+ (0x00000192, 0x0000714e)
+
+ (0x00001f83, 0x00004e32)
+ 1
+
+
+ (0x000078f9, 0x000063eb)
+ 0
+
+
+
+ (0x00001717, 0x00003cf9)
+
+ (0x000078d0, 0x000029bc)
+ 0
+
+
+ (0x00000b2d, 0x00006d61)
+ 0
+
+
+
+ (0x00004674, 0x000061af)
+
+ (0x00007b56, 0x000033f9)
+ 0
+
+
+ (0x00000d41, 0x000013b7)
+ 0
+
+
+
+ (0x0ac1c4d1, 0x0a9429d6)
+
+ (0x000063a5, 0x0000197d)
+ 0
+
+
+ (0x000078d0, 0x000029bc)
+ 0
+
+
+
+ (0x0f719dbe, 0x6b9207ad)
+
+ (0x000078f9, 0x000063eb)
+ 0
+
+
+ (0x00002f94, 0x00000342)
+ 0
+
+
+
+ (0x175e412c, 0x0692f4ee)
+
+ (0x00000d41, 0x000013b7)
+ 0
+
+
+ (0x0a5a6a4a, 0x1d92a778)
+ 2
+
+
+
+ (0x26545f2f, 0x4e793786)
+
+ (0x000078f9, 0x000063eb)
+ 0
+
+
+ (0x000063a5, 0x0000197d)
+ 0
+
+
+
+ (0x26dbc15a, 0x2ae965d4)
+
+ (0x00001f83, 0x00004e32)
+ 2
+
+
+ (0x000063a5, 0x0000197d)
+ 1
+
+
+
+ (0x33c4df2d, 0x7548b76f)
+
+ (0x00001f83, 0x00004e32)
+ 2
+
+
+ (0x00002f94, 0x00000342)
+ 1
+
+
+
+ (0x431fd3b9, 0x43484889)
+
+ (0x00002f94, 0x00000342)
+ 0
+
+
+ (0x00007b56, 0x000033f9)
+ 0
+
+
+
+ (0x5a67b7d8, 0x1cf07f9a)
+
+ (0x00001f83, 0x00004e32)
+ 2
+
+
+ (0x0a5a6a4a, 0x1d92a778)
+ 0
+
+
+
+ (0x616495af, 0x5c020b32)
+
+ (0x0a5a6a4a, 0x1d92a778)
+ 0
+
+
+ (0x00002c8b, 0x000001d5)
+ 0
+
+
+
+ (0x63fa63da, 0x0e447c5b)
+
+ (0x00000b2d, 0x00006d61)
+ 0
+
+
+ (0x0a5a6a4a, 0x1d92a778)
+ 1
+
+
+
+
+
+ (0x00005277, 0x00007fbe)
+ <u><b><big>Scenario Overview</big></b></u>
+
+This scenario should be used to train
+the LDA classifier.
+
+At the end of the training, you will have an estimation
+of the classifier performance printed in the console.
+If this performance is lower than 70%, just run a new
+<i>4-online</i> session to have better results.
+
+<u><b>Note:</b></u> in order to run this scenario,
+the spatial filter should have been trained using
+<i>2-train-xDAWN</i> !
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 688
+
+
+ (0x7234b86b, 0x2b8651a5)
+ -64
+
+
+
+
+
+
+ (0x0000775c, 0x000078ff)
+ (0x3bcce5d2, 0x43f2d968)
+ []
+
+
+
+
+ (0x790d75b8, 0x3bb90c33)
+ Yann Renard
+
+
+ (0x8c1fc55b, 0x7b433dc2)
+
+
+
+ (0x9f5c4075, 0x4a0d3666)
+ LDA Classifier Trainer
+
+
+ (0xf36a1567, 0xd13c53da)
+ http://openvibe.inria.fr/p300-speller-xdawn/
+
+
+ (0xf6b2e3fa, 0x7bd43926)
+ xDAWN P300 Speller
+
+
+ (0xf8034a49, 0x8b3f37cc)
+ INRIA
+
+
+
\ No newline at end of file
diff --git a/scenarios/p300-tactile-4-online.xml b/scenarios/p300-tactile-4-online.xml
new file mode 100644
index 0000000..8ec6b05
--- /dev/null
+++ b/scenarios/p300-tactile-4-online.xml
@@ -0,0 +1,1772 @@
+
+ 2
+ OpenViBE Designer
+ 3.3.0
+
+
+
+
+
+ (0x00002bb3, 0x0000133c)
+ Acquisition client
+ (0x35d225cb, 0x3e6e3a5f)
+
+
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Acquisition server hostname
+ ${AcquisitionServer_HostName}
+ ${ACQUISITION_SERVER_HOST_NAME}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Acquisition server port
+ 1024
+ ${ACQUISITION_SERVER_PORT}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ -224
+
+
+ (0x207c9054, 0x3c841b63)
+ 592
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x0d4656c0, 0xc95b1fa8)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x007036bf)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xc80ce8af, 0xf699f813)
+ 5
+
+
+ (0xce18836a, 0x9c0eb403)
+ 2
+
+
+
+
+ (0x00003d0e, 0x000025ef)
+ Player Controller
+ (0x5f426dce, 0x08456e13)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation name
+ OVTK_StimulationId_Label_00
+ OVTK_StimulationId_ExperimentStop
+ false
+
+
+ (0xcc14d8d6, 0xf27ecb73)
+ Action to perform
+ Pause
+ Stop
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 240
+
+
+ (0x207c9054, 0x3c841b63)
+ 896
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x568d148e, 0x650792b3)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xce18836a, 0x9c0eb403)
+ 2
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x00003dec, 0x00004c7c)
+ Stimulation based epoching
+ (0x426163d1, 0x324237b0)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stimulations
+
+
+
+
+
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch duration (in sec)
+ 1
+ 0.6
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Epoch offset (in sec)
+ 0.5
+ 0
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Stimulation to epoch from
+ OVTK_GDF_VEP
+ OVTK_StimulationId_VisualStimulationStart
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 208
+
+
+ (0x207c9054, 0x3c841b63)
+ 512
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x5de31172, 0xa1304456)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x005ced91)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xc80ce8af, 0xf699f813)
+ 2
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 2
+
+
+
+
+ (0x0000445b, 0x000068e3)
+ P300 accumulator
+ (0x0b5a2787, 0x02750621)
+
+
+ (0x6f752dd0, 0x082a321e)
+ New input
+
+
+ (0x6f752dd0, 0x082a321e)
+ New input(1)
+
+
+
+
+
+
+
+ (0xb0d0db45, 0x49cbc34a)
+ Lua Script
+
+ ${SCRIPT_P300_ACCUMULATOR}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Row stimulation base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ OVTK_StimulationId_Label_07
+ ${N_TACTILOS}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Segment start
+ OVTK_StimulationId_SegmentStart
+ OVTK_StimulationId_TrialStart
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Segment stop
+ OVTK_StimulationId_SegmentStop
+ OVTK_StimulationId_TrialStop
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 480
+
+
+ (0x207c9054, 0x3c841b63)
+ 640
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xd6e3f48b, 0xbee3523a)
+
+
+ (0x61d11811, 0x71e65362)
+
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x0304fb88)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 1
+
+
+ (0xf191c1c8, 0xa0123976)
+
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x000046bc, 0x00003f08)
+ Temporal Filter
+ (0xb4f9d042, 0x9d79f2e5)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0xfa20178e, 0x4cba62e9)
+ Filter Type
+ Band Pass
+ ${FILTER_TYPE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Filter Order
+ 4
+ ${FILTER_ORDER}
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Low Cut-off Frequency (Hz)
+ 1
+ ${LOW_CUT_FREQUENCY}
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ High Cut-off Frequency (Hz)
+ 40
+ ${HIGH_CUT_FREQUENCY}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ -32
+
+
+ (0x207c9054, 0x3c841b63)
+ 480
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x6a7c1e9b, 0x6b00b5c5)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 4
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x0000470b, 0x00001b1d)
+ Tactile Stimulator
+ (0x0b5a2787, 0x02750621)
+
+
+
+
+
+ (0xb0d0db45, 0x49cbc34a)
+ Lua Script
+
+ ${SCRIPT_TACTILE_STIMULATOR}
+ false
+
+
+ (0x00000000, 0xbae13066)
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x00000000, 0xc152613d)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+ (0x00000000, 0xa0308929)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Repetitions
+ 6
+ ${N_REPETITIONS}
+ false
+
+
+ (0x00000000, 0xcde95a6f)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Trials
+ 6
+ ${N_TRIALS}
+ false
+
+
+ (0x00000000, 0x9b3f9b7b)
+ (0x512a166f, 0x5c3ef83f)
+ Stimulus Duration (in sec)
+ 0.2
+ ${STIM_DURATION}
+ false
+
+
+ (0x00000000, 0x583ad367)
+ (0x512a166f, 0x5c3ef83f)
+ No Stimulus Duration (in sec)
+ 0.1
+ ${NO_STIM_DURATION}
+ false
+
+
+ (0x00000000, 0xfc1c2fb6)
+ (0x512a166f, 0x5c3ef83f)
+ Inter-Repetition Delay (in sec)
+ 1.0
+ ${INTER_REPETITION_DELAY}
+ false
+
+
+ (0x00000000, 0x0d9a1e18)
+ (0x512a166f, 0x5c3ef83f)
+ Inter-Trial Delay (in sec)
+ 3.0
+ ${INTER_TRIAL_DELAY}
+ false
+
+
+ (0x00000000, 0xaeefd500)
+ (0x2c132d6e, 0x44ab0d97)
+ Start Stimulation
+ OVTK_StimulationId_Label_00
+ ${START_STIMULATION}
+ false
+
+
+ (0x00000000, 0xef5eb0e5)
+ (0x2cdb2f0b, 0x12f231ea)
+ Free Spelling
+ false
+ ${FREE_SPELLING}
+ false
+
+
+ (0x00000000, 0x4ead155d)
+ (0x007deef9, 0x2f3e95c6)
+ Start Delay
+ 20
+ ${START_DELAY}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 336
+
+
+ (0x207c9054, 0x3c841b63)
+ 352
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xd6e3f48b, 0xbee3523a)
+
+
+ (0x61d11811, 0x71e65362)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 1
+
+
+ (0xf191c1c8, 0xa0123976)
+
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00006d0d, 0x000031da)
+ Tactile Target Generation
+ (0x0b5a2787, 0x02750621)
+
+
+ (0x6f752dd0, 0x082a321e)
+ New input
+
+
+
+
+
+
+
+ (0xb0d0db45, 0x49cbc34a)
+ Lua Script
+
+ ${SCRIPT_TARGET_GENERATION}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x00000000, 0xeb4fffa2)
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+ (0xf33dddda, 0xfd2c04a3)
+ (0x007deef9, 0x2f3e95c6)
+ Delay Before Sending (in sec)
+ 2
+ ${SEND_DELAY}
+ false
+
+
+ (0xa95b0b1d, 0x12aa8207)
+ (0x2cdb2f0b, 0x12f231ea)
+ Free Spelling
+ false
+ ${FREE_SPELLING}
+ false
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 496
+
+
+ (0x207c9054, 0x3c841b63)
+ 432
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xd6e3f48b, 0xbee3523a)
+
+
+ (0x61d11811, 0x71e65362)
+
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x0334c6b7)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 1
+
+
+ (0xf191c1c8, 0xa0123976)
+
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x00007e4e, 0x00006b7c)
+ EEG Signal
+ (0x0055be5f, 0x087bdd12)
+
+
+ (0x5ba36127, 0x195feae1)
+ Data
+
+
+ (0x6f752dd0, 0x082a321e)
+ Stimulations
+
+
+ (0x6ab26b81, 0x0f8c02f3)
+ Channel Units
+
+
+
+
+ (0x5de046a6, 0x086340aa)
+ Display Mode
+ Scan
+ Scan
+ false
+
+
+ (0x33a30739, 0x00d5299b)
+ Auto vertical scale
+ Per channel
+ Per channel
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Scale refresh interval (secs)
+ 5
+ 0.000000
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Scale
+ 100
+ 100
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Vertical Offset
+ 0
+ 0
+ false
+
+
+ (0x512a166f, 0x5c3ef83f)
+ Time Scale
+ 10
+ 5.000000
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Horizontal ruler
+ true
+ true
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Vertical ruler
+ false
+ false
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Multiview
+ false
+ false
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 304
+
+
+ (0x207c9054, 0x3c841b63)
+ 832
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x92c056a7, 0x2dc71aff)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xce18836a, 0x9c0eb403)
+ 9
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 3
+
+
+
+
+ (0x008f57e1, 0x2790537b)
+ Generic stream writer
+ (0x09c92218, 0x7c1216f8)
+
+
+ (0x403488e7, 0x565d70b6)
+ Input stream 1
+
+
+ (0x5ba36127, 0x195feae1)
+ Input stream 2
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stream 3
+
+
+
+
+ (0x330306dd, 0x74a95f98)
+ Filename
+
+ ${OUTPUT_FILE_NAME}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Use compression
+ false
+ false
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 368
+
+
+ (0x207c9054, 0x3c841b63)
+ 768
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x89a08108, 0xc8d1fac1)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x007b2629)
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x09c41dd7, 0x09f2e37b)
+ Epoch average
+ (0x21283d9f, 0xe76ff640)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input epochs
+
+
+
+
+
+
+
+ (0x6530bdb1, 0xd057bbfe)
+ Averaging type
+ Epoch block average
+ Epoch block average
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Epoch count
+ 4
+ 1
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 272
+
+
+ (0x207c9054, 0x3c841b63)
+ 512
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xb73cee83, 0xf7215d60)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0x8d21ff41, 0xdf6afe7e)
+ ${Player_ScenarioDirectory}/cfg/p300-epoch-average.cfg
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x000eaa12)
+
+
+
+
+ (0x0e30a73f, 0x7ae6d95a)
+ Feature aggregator
+ (0x00682417, 0x453635f9)
+
+
+ (0x544a003e, 0x6dcba5f6)
+ Input stream 1
+
+
+
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 336
+
+
+ (0x207c9054, 0x3c841b63)
+ 512
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xb5d15cc9, 0x6c8c28fb)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x000f9a38)
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+ (0x1d17831e, 0x729cda7c)
+ Tactilo Controller
+ (0x823bbe28, 0x0daf2111)
+
+
+ (0x6f752dd0, 0x082a321e)
+ StimInput
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Serial Port Name
+ /dev/ttyACM0
+ ${SERIAL_PORT}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 496
+
+
+ (0x207c9054, 0x3c841b63)
+ 272
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xa638e513, 0x9a753d4b)
+
+
+ (0x666fffff, 0x666fffff)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x28b5e192, 0x37431137)
+ Classifier processor
+ (0x5fe23d17, 0x95b0452c)
+
+
+ (0x17341935, 0x152ff448)
+ Features
+
+
+ (0x6f752dd0, 0x082a321e)
+ Commands
+
+
+
+
+
+
+
+
+
+ (0x330306dd, 0x74a95f98)
+ Filename to load configuration from
+
+ ${CLASSIFIER_CONFIG}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 400
+
+
+ (0x207c9054, 0x3c841b63)
+ 576
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xa6c8e548, 0x9e3e405b)
+
+
+ (0xc73e83ec, 0xf855c5bc)
+ false
+
+
+ (0xc80ce8af, 0xf699f813)
+ 3
+
+
+ (0xce18836a, 0x9c0eb403)
+ 1
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 2
+
+
+
+
+ (0x2ae25693, 0x5aacdae0)
+ P300TactileVisualization
+ (0xd463df86, 0x7fbfdd81)
+
+
+ (0x6f752dd0, 0x082a321e)
+ Sequence
+
+
+ (0x6f752dd0, 0x082a321e)
+ Target
+
+
+ (0x6f752dd0, 0x082a321e)
+ Result
+
+
+
+
+
+
+
+ (0x330306dd, 0x74a95f98)
+ Interface Filename
+ /ui/p300-tactile-6.ui
+ ${TACTILE_UI}
+ false
+
+
+ (0x2c132d6e, 0x44ab0d97)
+ Row Stimulation Base
+ OVTK_StimulationId_Label_01
+ ${ROW_BASE}
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Tactilos
+ 6
+ ${N_TACTILOS}
+ false
+
+
+ (0x2cdb2f0b, 0x12f231ea)
+ Free Spelling
+ false
+ ${FREE_SPELLING}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 640
+
+
+ (0x207c9054, 0x3c841b63)
+ 368
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x4b4912a1, 0xc1409d95)
+
+
+ (0x666fffff, 0x666fffff)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 4
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 3
+
+
+
+
+ (0x40e41bf9, 0x5c44b1b1)
+ Signal Decimation
+ (0x012f4bea, 0x3be37c66)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Decimation factor
+ 8
+ ${SIGNAL_DECIMATION_FACTOR}
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 32
+
+
+ (0x207c9054, 0x3c841b63)
+ 480
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x5082af41, 0xd0fbf4cb)
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x002cae02)
+
+
+
+
+ (0x4ff47ca1, 0x133bd33c)
+ EEG Channel Selection
+ (0x361722e8, 0x311574e8)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input signal
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Channel List
+ :
+ ${CHANNEL_SELECTION}
+ false
+
+
+ (0x3bcf9e67, 0x0c23994d)
+ Action
+ Select
+ Select
+ false
+
+
+ (0x666f25e9, 0x3e5738d6)
+ Channel Matching Method
+ Smart
+ Index
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ -112
+
+
+ (0x207c9054, 0x3c841b63)
+ 480
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x277826e1, 0xa30a3bd0)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x6d03daab, 0x55fdea78)
+ xDAWN Spatial Filter
+ (0xdd332c6c, 0x195b4fd4)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input Signal
+
+
+
+
+
+
+
+ (0x79a9edeb, 0x245d83fc)
+ Spatial Filter Coefficients
+ 1;0;0;0;0;1;0;0;0;0;1;0;0;0;0;1
+ 1;0;0;0;0;1;0;0;0;0;1;0;0;0;0;1
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Output Channels
+ 4
+ 4
+ false
+
+
+ (0x007deef9, 0x2f3e95c6)
+ Number of Input Channels
+ 4
+ 4
+ false
+
+
+ (0x330306dd, 0x74a95f98)
+ Filter matrix file
+
+
+ false
+
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 112
+
+
+ (0x207c9054, 0x3c841b63)
+ 480
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0x81db9bf9, 0xf1cf4ed7)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0x8d21ff41, 0xdf6afe7e)
+ ${SPATIAL_FILTER_CONFIG}
+
+
+ (0xc80ce8af, 0xf699f813)
+ 1
+
+
+ (0xce18836a, 0x9c0eb403)
+ 3
+
+
+ (0xcfad85b0, 0x7c6d841c)
+ 1
+
+
+
+
+ (0x6f54afd0, 0x5f2e0f65)
+ Identity
+ (0x5dffe431, 0x35215c50)
+
+
+ (0x5ba36127, 0x195feae1)
+ Input stream 1
+
+
+ (0x6f752dd0, 0x082a321e)
+ Input stream 2
+
+
+
+
+
+
+
+
+ (0x17ee7c08, 0x94c14893)
+
+
+
+ (0x1fa7a38f, 0x54edbe0b)
+ 112
+
+
+ (0x207c9054, 0x3c841b63)
+ 640
+
+
+ (0x30a4e5c9, 0x83502953)
+
+
+
+ (0x4e7b798a, 0x183beafb)
+ (0xa8ffe2a3, 0x27038f03)
+
+
+ (0x527ad68d, 0x16d746a0)
+
+
+
+ (0xc46b3d00, 0x3e0454e1)
+ (0x00000000, 0x005f48d2)
+
+
+ (0xfba64161, 0x65304e21)
+
+
+
+
+
+
+
+ (0x000077c1, 0x00007142)
+
+ (0x0000470b, 0x00001b1d)
+ 0
+
+
+ (0x00006d0d, 0x000031da)
+ 0
+
+
+
+ (0x00f1a11e, 0x4a813bb8)
+
+ (0x09c41dd7, 0x09f2e37b)
+ 0
+
+
+ (0x0e30a73f, 0x7ae6d95a)
+ 0
+
+
+
+ (0x03185e43, 0x2d6b648b)
+
+ (0x00002bb3, 0x0000133c)
+ 1
+
+
+ (0x4ff47ca1, 0x133bd33c)
+ 0
+
+
+
+ (0x0d9c8913, 0x36d55346)
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 1
+
+
+ (0x00003dec, 0x00004c7c)
+ 1
+
+
+
+ (0x11e063ca, 0x16409346)
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 1
+
+
+ (0x008f57e1, 0x2790537b)
+ 2
+
+
+
+ (0x136dcee0, 0x20dbb005)
+
+ (0x28b5e192, 0x37431137)
+ 0
+
+
+ (0x0000445b, 0x000068e3)
+ 0
+
+
+
+ (0x1b32ea4c, 0x7ba0dd1f)
+
+ (0x00006d0d, 0x000031da)
+ 0
+
+
+ (0x2ae25693, 0x5aacdae0)
+ 1
+
+
+
+ (0x1cd8fa10, 0x3aaa591e)
+
+ (0x1d17831e, 0x729cda7c)
+ 0
+
+
+ (0x2ae25693, 0x5aacdae0)
+ 0
+
+
+
+ (0x1e3b6579, 0x3618d582)
+
+ (0x0000445b, 0x000068e3)
+ 0
+
+
+ (0x2ae25693, 0x5aacdae0)
+ 2
+
+
+
+ (0x2dd9e520, 0x7fb52ca6)
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 1
+
+
+ (0x00003d0e, 0x000025ef)
+ 0
+
+
+
+ (0x365ba47b, 0x4e08a9a6)
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 1
+
+
+ (0x00007e4e, 0x00006b7c)
+ 1
+
+
+
+ (0x3aa31050, 0x44840533)
+
+ (0x00003dec, 0x00004c7c)
+ 0
+
+
+ (0x09c41dd7, 0x09f2e37b)
+ 0
+
+
+
+ (0x3ccbcbed, 0x529f3e1d)
+
+ (0x0e30a73f, 0x7ae6d95a)
+ 0
+
+
+ (0x28b5e192, 0x37431137)
+ 0
+
+
+
+ (0x58177d03, 0x27416662)
+
+ (0x40e41bf9, 0x5c44b1b1)
+ 0
+
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 0
+
+
+
+ (0x5f9d3b5e, 0x40ac0989)
+
+ (0x000046bc, 0x00003f08)
+ 0
+
+
+ (0x40e41bf9, 0x5c44b1b1)
+ 0
+
+
+
+ (0x650a90ae, 0x221065dd)
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 0
+
+
+ (0x00007e4e, 0x00006b7c)
+ 0
+
+
+
+ (0x6b1a8e7e, 0x29bad5ad)
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 0
+
+
+ (0x008f57e1, 0x2790537b)
+ 1
+
+
+
+ (0x6f474af0, 0x51e7edd2)
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 1
+
+
+ (0x0000445b, 0x000068e3)
+ 1
+
+
+
+ (0x734979ea, 0x23bfc8a8)
+
+ (0x6d03daab, 0x55fdea78)
+ 0
+
+
+ (0x00003dec, 0x00004c7c)
+ 0
+
+
+
+ (0x7513c06a, 0x64166fa5)
+
+ (0x0000470b, 0x00001b1d)
+ 0
+
+
+ (0x1d17831e, 0x729cda7c)
+ 0
+
+
+
+ (0x798e3c9f, 0x6cbe6777)
+
+ (0x40e41bf9, 0x5c44b1b1)
+ 0
+
+
+ (0x6d03daab, 0x55fdea78)
+ 0
+
+
+
+ (0x7b323c0e, 0x1ee91fad)
+
+ (0x4ff47ca1, 0x133bd33c)
+ 0
+
+
+ (0x000046bc, 0x00003f08)
+ 0
+
+
+
+ (0x7cd9ce5c, 0x13f0d05b)
+
+ (0x00002bb3, 0x0000133c)
+ 2
+
+
+ (0x6f54afd0, 0x5f2e0f65)
+ 1
+
+
+
+
+
+ (0x0000363f, 0x00001c2b)
+ The P300 Speller Visualization
+sends the markers (stimulations) directly to
+Acquisition Server using TCP Tagging.
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 624
+
+
+ (0x7234b86b, 0x2b8651a5)
+ 640
+
+
+
+
+ (0x1012e1de, 0x78e57c3e)
+ The stimulation part of the scenario is
+similar to scenario <i>p300-tactile-1-acquisition</i>.
+
+If set to <i>Free Spelling</i>,
+the <i>Target Generation</i> is inactive.
+
+If set to <i>Copy Spelling</i>, you can train the spatial-filter
+and p300-classifier again on the recorded data
+
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 64
+
+
+ (0x7234b86b, 0x2b8651a5)
+ 480
+
+
+
+
+ (0x3726b6f5, 0x3dea5d78)
+ <u><b><big>Scenario Overview</big></b></u>
+
+This scenario can be used online once the
+spatial filter and the classifiers are trained.
+
+Can be used for <i>Copy Spelling</i> to retrain
+the <i>spatial filter</i> and <i>classifier</i>, if the
+performance doesn't fit the requirements.
+Can be used for a <i>Free Spelling</i> Session.
+
+Spelling automatically starts delayed to the start
+of scenario execution.
+
+First the target Tactilo will vibrate and flash in the
+<i>Speller Visualization</i>(Copy Spelling Only).
+After that you have to Focus on your chosen
+(or the predetermined Target), while all Tactilos
+will vibrate (flash) several times.
+This will be repeated for a defined number of trials.
+After each Trial, the detected Tactilo will be presented
+in the <i>Speller Visualization</i>
+
+
+ (0x473d9a43, 0x97fc0a97)
+ 80
+
+
+ (0x7234b86b, 0x2b8651a5)
+ 0
+
+
+
+
+
+
+ (0x0000775c, 0x000078ff)
+ (0x3bcce5d2, 0x43f2d968)
+ [{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":2,"height":320,"identifier":"(0x00001d01, 0x00007b57)","name":"OV Tactile Online","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":477},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00001590, 0x00005323)","index":0,"name":"Tactile Visualization","parentIdentifier":"(0x00001d01, 0x00007b57)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00002e00, 0x00003101)","index":1,"name":"EEG Signal","parentIdentifier":"(0x00001d01, 0x00007b57)","type":2},{"boxIdentifier":"(0x2ae25693, 0x5aacdae0)","childCount":0,"identifier":"(0x01033ddc, 0x12635d14)","index":0,"parentIdentifier":"(0x00001590, 0x00005323)","type":3},{"boxIdentifier":"(0x00007e4e, 0x00006b7c)","childCount":0,"identifier":"(0x00001aa9, 0x000006f8)","index":0,"parentIdentifier":"(0x00002e00, 0x00003101)","type":3}]
+
+
+
+
+ (0x790d75b8, 0x3bb90c33)
+ Jussi T. Lindgren
+
+
+ (0x8c1fc55b, 0x7b433dc2)
+
+
+
+ (0x9f5c4075, 0x4a0d3666)
+ Online Use
+
+
+ (0xf36a1567, 0xd13c53da)
+ http://openvibe.inria.fr/p300-speller-xdawn/
+
+
+ (0xf6b2e3fa, 0x7bd43926)
+ xDAWN P300 Speller
+
+
+ (0xf8034a49, 0x8b3f37cc)
+ INRIA
+
+
+
\ No newline at end of file
diff --git a/scenarios/scripts/p300-tactile-accumulator.lua b/scenarios/scripts/p300-tactile-accumulator.lua
new file mode 100644
index 0000000..94130c2
--- /dev/null
+++ b/scenarios/scripts/p300-tactile-accumulator.lua
@@ -0,0 +1,202 @@
+
+function arrayMax(a)
+ if #a == 0 then return nil, nil end
+ local maxIdx, maxValue = 0, a[0]
+ for i = 1, (#a -1 ) do
+ if maxValue < a[i] then
+ maxIdx, maxValue = i, a[i]
+ end
+ end
+ return maxIdx, maxValue
+end
+
+-- For handling target fifo
+
+List = {}
+function List.new ()
+ return {first = 0, last = -1}
+end
+
+function List.pushright (list, value)
+ local last = list.last + 1
+ list.last = last
+ list[last] = value
+end
+
+function List.popleft (list)
+ local first = list.first
+ if first > list.last then
+ error("list is empty")
+ end
+ local value = list[first]
+ list[first] = nil -- to allow garbage collection
+ list.first = first + 1
+ return value
+end
+
+function List.isempty (list)
+ if list.first > list.last then
+ return true
+ else
+ return false
+ end
+end
+
+-- this function is called when the box is initialized
+function initialize(box)
+
+ dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
+
+ row_base = _G[box:get_setting(2)]
+ n_tactilos = box:get_setting(3)
+ segment_start = _G[box:get_setting(4)]
+ segment_stop = _G[box:get_setting(5)]
+
+ col_base = row_base + n_tactilos
+
+ -- 0 inactive, 1 segment started, 2 segment stopped (can vote)
+ segment_status = 0
+
+ -- the idea is to push the flash states to the fifo, and when predictions arrive (with some delay), they are matched in oldest-first fashion.
+ target_fifo = List.new()
+
+ -- box:log("Info", string.format("pop %d %d", id[1], id[2]))
+
+ row_votes = {}
+ col_votes = {}
+
+ do_debug = false
+
+end
+
+-- this function is called when the box is uninitialized
+function uninitialize(box)
+
+end
+
+function process(box)
+ -- loops until box is stopped
+ while box:keep_processing() do
+
+ -- first, parse the timeline stream
+ for stimulation = 1, box:get_stimulation_count(2) do
+ -- gets the received stimulation
+ local identifier, date, duration = box:get_stimulation(2, 1)
+ -- discards it
+ box:remove_stimulation(2, 1)
+
+ if identifier == segment_start then
+ if do_debug then
+ box:log("Info", string.format("Trial start"))
+ box:log("Info", string.format("Clear votes"))
+ end
+ -- zero the votes
+ col_votes = {}
+ row_votes = {}
+ target_fifo = List.new()
+ -- fixme fixed 20
+ for i = 0,20 do
+ col_votes[i] = 0
+ row_votes[i] = 0
+ end
+ segment_status = 1
+ end
+
+ -- Does the identifier code a flash? if so, put into fifo
+ if segment_status == 1 and identifier >= row_base and identifier <= OVTK_StimulationId_LabelEnd then
+
+ -- assume rows before cols
+ if identifier < col_base then
+ local t = {"row", identifier - row_base}
+ List.pushright(target_fifo,t)
+ if do_debug then
+ box:log("Info", string.format("Push row target %d", identifier - row_base ))
+ end
+ else
+ local t = {"col", identifier - col_base}
+ List.pushright(target_fifo,t)
+ if do_debug then
+ box:log("Info", string.format("Push col target %d", identifier - col_base ))
+ end
+ end
+
+
+ end
+
+ if identifier == segment_stop then
+ if do_debug then
+ box:log("Info", string.format("Trial stop"))
+ end
+ segment_status = 2
+ end
+
+ end
+
+ -- then parse the classifications
+ for stimulation = 1, box:get_stimulation_count(1) do
+
+ -- gets the received stimulation
+ local identifier, date, duration = box:get_stimulation(1, 1)
+ -- discards it
+ box:remove_stimulation(1, 1)
+
+ -- Is it an in-class prediction?
+ if identifier == OVTK_StimulationId_Target then
+ local t = List.popleft(target_fifo)
+ if do_debug then
+ box:log("Info", string.format("Pred fifo %s %d is target", t[1], t[2]))
+ end
+ if t[1]=="row" then
+ row_votes[t[2]] = row_votes[t[2]] + 1
+ else
+ col_votes[t[2]] = col_votes[t[2]] + 1
+ end
+ end
+
+ if identifier == OVTK_StimulationId_NonTarget then
+ local t = List.popleft(target_fifo)
+ if do_debug then
+ box:log("Info", string.format("Pred fifo %s %d is nontarget", t[1], t[2]))
+ end
+ end
+
+ end
+
+ if segment_status == 2 and List.isempty(target_fifo) then
+ -- output the vote after the segment end when we've matched all predictions
+
+ local maxRowIdx, maxRowValue = arrayMax(row_votes)
+ local maxColIdx, maxColValue = arrayMax(col_votes)
+
+ if maxRowValue == 0 and maxColValue == 0 then
+ box:log("Warning", string.format("Classifier predicted 'no p300' for all flashes of the trial"));
+ end
+
+ if do_debug then
+ local rowVotes = 0
+ local colVotes = 0
+ for ir, val in pairs(row_votes) do
+ rowVotes = rowVotes + val
+ end
+ for ir, val in pairs(col_votes) do
+ colVotes = colVotes + val
+ end
+
+ box:log("Info", string.format("Vote [%d %d] wt [%d,%d]", maxRowIdx+row_base, maxColIdx+col_base, maxRowValue, maxColValue))
+ box:log("Info", string.format(" Total [%d %d]", rowVotes, colVotes))
+ end
+
+
+
+ local now = box:get_current_time()
+
+ box:send_stimulation(1, maxRowIdx + row_base, now, 0)
+ -- box:send_stimulation(2, maxColIdx + col_base, now, 0)
+
+ segment_status = 0
+ end
+
+ box:sleep()
+ end
+end
+
diff --git a/scenarios/scripts/p300-tactile-filter-flash.lua b/scenarios/scripts/p300-tactile-filter-flash.lua
new file mode 100644
index 0000000..846bd55
--- /dev/null
+++ b/scenarios/scripts/p300-tactile-filter-flash.lua
@@ -0,0 +1,61 @@
+
+-- Picks out 'flashes' from a stimulation stream
+
+-- this function is called when the box is initialized
+function initialize(box)
+
+ dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
+
+ box:set_filter_mode(1);
+
+ state = 0
+
+ do_debug = false
+end
+
+-- this function is called when the box is uninitialized
+function uninitialize(box)
+end
+
+-- this function is called once by the box
+function process(box)
+
+ -- loop until box:keep_processing() returns zero
+ -- cpu will be released with a call to sleep
+ -- at the end of the loop
+ while box:keep_processing() do
+
+ -- gets current simulated time
+ t = box:get_current_time()
+
+ -- loops on every received stimulation for a given input
+ for stimulation = 1, box:get_stimulation_count(1) do
+
+ -- gets stimulation
+ stimulation_id, stimulation_time, stimulation_duration = box:get_stimulation(1, 1)
+
+ if stimulation_id == OVTK_StimulationId_SegmentStart then
+ state = 1
+ elseif stimulation_id == OVTK_StimulationId_SegmentStop then
+ state = 0
+ end
+
+ -- If we're between 'rest start' and 'rest_stop', this specifies a target
+ if state == 1 and stimulation_id >= OVTK_StimulationId_LabelStart and stimulation_id <= OVTK_StimulationId_LabelEnd then
+
+ box:send_stimulation(1, stimulation_id, stimulation_time, 0)
+
+ if do_debug then
+ box:log("Info", string.format("Push a target %d at %f (now %f)", stimulation_id, stimulation_time, t))
+ end
+ end
+
+ -- discards it
+ box:remove_stimulation(1, 1)
+
+ end
+
+ -- releases cpu
+ box:sleep()
+ end
+end
diff --git a/scenarios/scripts/p300-tactile-filter-target.lua b/scenarios/scripts/p300-tactile-filter-target.lua
new file mode 100644
index 0000000..3a67c76
--- /dev/null
+++ b/scenarios/scripts/p300-tactile-filter-target.lua
@@ -0,0 +1,61 @@
+
+-- Picks out 'targets' from a stimulation stream
+
+-- this function is called when the box is initialized
+function initialize(box)
+
+ dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
+
+ state = 0
+
+ box:set_filter_mode(1);
+
+ do_debug = false
+end
+
+-- this function is called when the box is uninitialized
+function uninitialize(box)
+end
+
+-- this function is called once by the box
+function process(box)
+
+ -- loop until box:keep_processing() returns zero
+ -- cpu will be released with a call to sleep
+ -- at the end of the loop
+ while box:keep_processing() do
+
+ -- gets current simulated time
+ t = box:get_current_time()
+
+ -- loops on every received stimulation for a given input
+ for stimulation = 1, box:get_stimulation_count(1) do
+
+ -- gets stimulation
+ stimulation_id, stimulation_time, stimulation_duration = box:get_stimulation(1, 1)
+
+ if stimulation_id == OVTK_StimulationId_RestStart then
+ state = 1
+ elseif stimulation_id == OVTK_StimulationId_RestStop then
+ state = 0
+ end
+
+ -- If we're between 'rest start' and 'rest_stop', this specifies a target
+ if state == 1 and stimulation_id >= OVTK_StimulationId_LabelStart and stimulation_id <= OVTK_StimulationId_LabelEnd then
+
+ box:send_stimulation(1, stimulation_id, stimulation_time, 0)
+
+ if do_debug then
+ box:log("Info", string.format("Push a target %d at %f (now = %f)", stimulation_id, stimulation_time, t))
+ end
+ end
+
+ -- discards it
+ box:remove_stimulation(1, 1)
+
+ end
+
+ -- releases cpu
+ box:sleep()
+ end
+end
diff --git a/scenarios/scripts/p300-tactile-launch.lua b/scenarios/scripts/p300-tactile-launch.lua
new file mode 100644
index 0000000..8c65efb
--- /dev/null
+++ b/scenarios/scripts/p300-tactile-launch.lua
@@ -0,0 +1,21 @@
+
+-- this function is called when the box is initialized
+function initialize(box)
+
+ dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
+
+ stim = _G[box:get_setting(2)]
+ launchTime = box:get_setting(3)
+
+end
+
+-- this function is called when the box is uninitialized
+function uninitialize(box)
+end
+
+-- this function is called once by the box
+function process(box)
+
+ box:send_stimulation(1, stim, launchTime, 0)
+
+end
diff --git a/scenarios/scripts/p300-tactile-stimulator.lua b/scenarios/scripts/p300-tactile-stimulator.lua
new file mode 100644
index 0000000..f3be955
--- /dev/null
+++ b/scenarios/scripts/p300-tactile-stimulator.lua
@@ -0,0 +1,138 @@
+-- This Lua script sends Stimulations to the speller visualization box for a tactile p300-System with 6 stimulators
+--
+-- Author : Tobias Baumann
+-- Date : 2021-12-06
+-- Revised: 2021-19-11
+
+--This function lets the box sleep until a fixed moment
+function wait_until(box, time)
+ while box:get_current_time() < time do
+ box:sleep()
+ end
+end
+
+--This function lets the box wait for a fixed duration
+function wait_for(box, duration)
+ wait_until(box, box:get_current_time() + duration)
+end
+
+--this function checks, wether value already is an element of the given stim_matrix
+function is_element(matrix, value)
+ for i = 1, #matrix do
+ if #matrix == 0 then
+ return(false)
+ elseif value == matrix[i] then
+ return(true)
+ end
+ end
+ return(false)
+end
+--this function creates a sequence of stimulations by shuffeling the values of the given stim_matrix
+function create_sequence(matrix)
+ local stim_matrix = {}
+ local stim_code = 0
+ local i = 1
+ while i <= #matrix do
+ stim_code = matrix[math.random(1,#matrix)]
+ if is_element(stim_matrix, stim_code) == false then
+ stim_matrix[i] = stim_code
+ i = i + 1
+ end
+ end
+ return(stim_matrix)
+end
+
+-- this function is called when the box is initialized
+function initialize(box)
+ --randomseed
+ math.randomseed(os.time())
+
+ --load stimulation codes
+ dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
+
+ --load box settings
+ row_base = _G[box:get_setting(2)]
+ n_tactilos = box:get_setting(3)
+ n_repetitions = box:get_setting(4)
+ n_trials = box:get_setting(5)
+ flash_duration = box:get_setting(6)
+ noflash_duration = box:get_setting(7)
+ inter_repetition_delay = box:get_setting(8)
+ inter_trial_delay = box:get_setting(9)
+ send_toggle = _G[box:get_setting(10)]
+ free_spelling = box:get_setting(11)
+ time_to_send = box:get_setting(12)
+
+ --Set number of trials to 1 in free spelling mode
+ if free_spelling == 'true' then
+ n_trials = 1
+ end
+
+ --Lua variables
+ send = false
+ experiment_end = false
+ tactilo_stimcodes = {}
+ for x = 1, n_tactilos do
+ tactilo_stimcodes[x] = row_base + x - 1
+ end
+end
+
+-- this function is called when the box is uninitialized
+function uninitialize(box)
+
+end
+
+-- this function is called once by the box
+function process(box)
+ while box:keep_processing() do
+
+ if send and not experiment_end then
+ -- iterate over the number of trials
+ for trial = 1, n_trials do
+ box:send_stimulation(1, OVTK_StimulationId_RestStart, box:get_current_time() , 0)
+ wait_for(box, inter_trial_delay)
+ box:send_stimulation(1, OVTK_StimulationId_RestStop, box:get_current_time() , 0)
+ box:send_stimulation(1, OVTK_StimulationId_TrialStart ,box:get_current_time() , 0)
+
+ -- iterate over the number of repetitions
+ for segment = 1, n_repetitions do
+ tactilo_stimcodes = create_sequence(tactilo_stimcodes)
+ box:send_stimulation(1, OVTK_StimulationId_SegmentStart ,box:get_current_time() , 0)
+
+ -- iterate over the number of tactilos
+ for i = 1, #tactilo_stimcodes do
+ box:send_stimulation(1, tactilo_stimcodes[i] ,box:get_current_time() , 0)
+ box:send_stimulation(1, OVTK_StimulationId_VisualStimulationStart ,box:get_current_time() , 0)
+ wait_for(box, flash_duration)
+ box:send_stimulation(1, OVTK_StimulationId_VisualStimulationStop ,box:get_current_time() , 0)
+ wait_for(box, noflash_duration)
+ end
+
+ box:send_stimulation(1, OVTK_StimulationId_SegmentStop ,box:get_current_time() , 0)
+ wait_for(box, inter_repetition_delay)
+ end
+
+ box:send_stimulation(1, OVTK_StimulationId_TrialStop ,box:get_current_time() , 0)
+
+ end
+
+ if free_spelling == 'false' then
+ -- end experiment if set to copy spelling
+ box:send_stimulation(1, OVTK_StimulationId_ExperimentStop ,box:get_current_time() , 0)
+ send = false
+ experiment_end = true
+ end
+
+ else if not send and not experiment_end then
+ -- delay the start of the experiment by t = time_to_send
+ wait_for(box, time_to_send)
+ send = true
+ box:send_stimulation(1, OVTK_StimulationId_ExperimentStart ,box:get_current_time() , 0)
+ end
+
+ end
+ -- releases cpu
+ box:sleep()
+ end
+
+end
diff --git a/scenarios/scripts/p300-tactile-target.lua b/scenarios/scripts/p300-tactile-target.lua
new file mode 100644
index 0000000..35d2f1e
--- /dev/null
+++ b/scenarios/scripts/p300-tactile-target.lua
@@ -0,0 +1,61 @@
+-- This Lua script generates target stimulations the 1x6 p300-tactile matrix
+--
+-- Author : Tobias Baumann
+-- Date : 2021-06-09
+
+-- this function is called when the box is initialized
+function initialize(box)
+
+ dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
+
+ math.randomseed(os.time())
+ row_base = _G[box:get_setting(2)]
+ n_tactilos = box:get_setting(3)
+ delay = box:get_setting(4)
+ free_spelling = box:get_setting(5)
+
+end
+
+-- this function is called when the box is uninitialized
+function uninitialize(box)
+end
+
+-- this function is called once by the box
+function process(box)
+
+ -- loop until box:keep_processing() returns zero
+ -- cpu will be released with a call to sleep
+ -- at the end of the loop
+ while box:keep_processing() do
+
+ -- gets current simulated time
+ t = box:get_current_time()
+
+ -- loops on every received stimulation for a given input
+ for stimulation = 1, box:get_stimulation_count(1) do
+
+ -- gets stimulation
+ stimulation_id, stimulation_time, stimulation_duration = box:get_stimulation(1, 1)
+
+ if free_spelling == 'false' then
+ if stimulation_id == OVTK_StimulationId_RestStart then
+
+ -- triggers the target
+ box:send_stimulation(1, row_base+math.random(1,n_tactilos)-1, t+delay, 0)
+
+ elseif stimulation_id == OVTK_StimulationId_ExperimentStop then
+
+ -- triggers train stimulation
+ box:send_stimulation(1, OVTK_StimulationId_Train, t+delay+1, 0)
+
+ end
+ end
+ -- discards it
+ box:remove_stimulation(1, 1)
+
+ end
+
+ -- releases cpu
+ box:sleep()
+ end
+end
diff --git a/scenarios/signals/README.txt b/scenarios/signals/README.txt
new file mode 100644
index 0000000..8eaa204
--- /dev/null
+++ b/scenarios/signals/README.txt
@@ -0,0 +1,3 @@
+
+The scenario will record its signals here.
+
diff --git a/scenarios/ui/p300-tactile-10.ui b/scenarios/ui/p300-tactile-10.ui
new file mode 100644
index 0000000..cff860b
--- /dev/null
+++ b/scenarios/ui/p300-tactile-10.ui
@@ -0,0 +1,321 @@
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-2.ui b/scenarios/ui/p300-tactile-2.ui
new file mode 100644
index 0000000..87a2999
--- /dev/null
+++ b/scenarios/ui/p300-tactile-2.ui
@@ -0,0 +1,185 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 2
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-3.ui b/scenarios/ui/p300-tactile-3.ui
new file mode 100644
index 0000000..efed83e
--- /dev/null
+++ b/scenarios/ui/p300-tactile-3.ui
@@ -0,0 +1,202 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 3
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+ True
+
+
+ True
+ Tactilo3
+ True
+ center
+
+
+
+
+ 2
+ 3
+
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-4.ui b/scenarios/ui/p300-tactile-4.ui
new file mode 100644
index 0000000..46a12f7
--- /dev/null
+++ b/scenarios/ui/p300-tactile-4.ui
@@ -0,0 +1,219 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 4
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+ True
+
+
+ True
+ Tactilo3
+ True
+ center
+
+
+
+
+ 2
+ 3
+
+
+
+
+ True
+
+
+ True
+ Tactilo4
+ True
+ center
+
+
+
+
+ 3
+ 4
+
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-5.ui b/scenarios/ui/p300-tactile-5.ui
new file mode 100644
index 0000000..a7783c4
--- /dev/null
+++ b/scenarios/ui/p300-tactile-5.ui
@@ -0,0 +1,235 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 5
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+ True
+
+
+ True
+ Tactilo3
+ True
+ center
+
+
+
+
+ 2
+ 3
+
+
+
+
+ True
+
+
+ True
+ Tactilo4
+ True
+ center
+
+
+
+
+ 3
+ 4
+
+
+
+
+ True
+
+
+ True
+ Tactilo5
+ True
+ center
+
+
+
+
+ 4
+ 5
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-6.ui b/scenarios/ui/p300-tactile-6.ui
new file mode 100644
index 0000000..f78ed23
--- /dev/null
+++ b/scenarios/ui/p300-tactile-6.ui
@@ -0,0 +1,253 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 6
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+ True
+
+
+ True
+ Tactilo3
+ True
+ center
+
+
+
+
+ 2
+ 3
+
+
+
+
+ True
+
+
+ True
+ Tactilo4
+ True
+ center
+
+
+
+
+ 3
+ 4
+
+
+
+
+ True
+
+
+ True
+ Tactilo5
+ True
+ center
+
+
+
+
+ 4
+ 5
+
+
+
+
+ True
+
+
+ True
+ Tactilo6
+ True
+ center
+
+
+
+
+ 5
+ 6
+
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-7.ui b/scenarios/ui/p300-tactile-7.ui
new file mode 100644
index 0000000..38447aa
--- /dev/null
+++ b/scenarios/ui/p300-tactile-7.ui
@@ -0,0 +1,270 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 7
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+ True
+
+
+ True
+ Tactilo3
+ True
+ center
+
+
+
+
+ 2
+ 3
+
+
+
+
+ True
+
+
+ True
+ Tactilo4
+ True
+ center
+
+
+
+
+ 3
+ 4
+
+
+
+
+ True
+
+
+ True
+ Tactilo5
+ True
+ center
+
+
+
+
+ 4
+ 5
+
+
+
+
+ True
+
+
+ True
+ Tactilo6
+ True
+ center
+
+
+
+
+ 5
+ 6
+
+
+
+
+ True
+
+
+ True
+ Tactilo7
+ True
+ center
+
+
+
+
+ 6
+ 7
+
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-8.ui b/scenarios/ui/p300-tactile-8.ui
new file mode 100644
index 0000000..af79af2
--- /dev/null
+++ b/scenarios/ui/p300-tactile-8.ui
@@ -0,0 +1,287 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 8
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+ True
+
+
+ True
+ Tactilo3
+ True
+ center
+
+
+
+
+ 2
+ 3
+
+
+
+
+ True
+
+
+ True
+ Tactilo4
+ True
+ center
+
+
+
+
+ 3
+ 4
+
+
+
+
+ True
+
+
+ True
+ Tactilo5
+ True
+ center
+
+
+
+
+ 4
+ 5
+
+
+
+
+ True
+
+
+ True
+ Tactilo6
+ True
+ center
+
+
+
+
+ 5
+ 6
+
+
+
+
+ True
+
+
+ True
+ Tactilo7
+ True
+ center
+
+
+
+
+ 6
+ 7
+
+
+
+
+ True
+
+
+ True
+ Tactilo8
+ True
+ center
+
+
+
+
+ 7
+ 8
+
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/scenarios/ui/p300-tactile-9.ui b/scenarios/ui/p300-tactile-9.ui
new file mode 100644
index 0000000..31ea839
--- /dev/null
+++ b/scenarios/ui/p300-tactile-9.ui
@@ -0,0 +1,304 @@
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+ True
+ 3
+ 4
+
+
+ True
+ 9
+ 1
+ True
+
+
+ True
+
+
+ True
+ Tactilo1
+ True
+ center
+
+
+
+
+ 1
+ 1
+
+
+
+
+ True
+
+
+ True
+ Tactilo2
+ True
+ center
+
+
+
+
+ 1
+ 2
+
+
+
+
+ True
+
+
+ True
+ Tactilo3
+ True
+ center
+
+
+
+
+ 2
+ 3
+
+
+
+
+ True
+
+
+ True
+ Tactilo4
+ True
+ center
+
+
+
+
+ 3
+ 4
+
+
+
+
+ True
+
+
+ True
+ Tactilo5
+ True
+ center
+
+
+
+
+ 4
+ 5
+
+
+
+
+ True
+
+
+ True
+ Tactilo6
+ True
+ center
+
+
+
+
+ 5
+ 6
+
+
+
+
+ True
+
+
+ True
+ Tactilo7
+ True
+ center
+
+
+
+
+ 6
+ 7
+
+
+
+
+ True
+
+
+ True
+ Tactilo8
+ True
+ center
+
+
+
+
+ 7
+ 8
+
+
+
+
+ True
+
+
+ True
+ Tactilo9
+ True
+ center
+
+
+
+
+ 8
+ 9
+
+
+
+
+
+
+ True
+ 2
+ 3
+ 4
+ 4
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ True
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Result :
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ 0
+ Target :
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+ True
+ gtk-select-font
+
+
+ 2
+
+
+
+
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+
+
+ 1
+ 2
+ GTK_FILL
+ GTK_FILL
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ P300 tactile
+ dialog
+
+
+ 640
+ True
+ both
+
+
+ True
+ Show Target Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ Show Result Text
+ gtk-info
+ True
+
+
+ False
+ True
+
+
+
+
+
+
diff --git a/src/TactileVisualization/TactileMenu.cpp b/src/TactileVisualization/TactileMenu.cpp
new file mode 100644
index 0000000..9194244
--- /dev/null
+++ b/src/TactileVisualization/TactileMenu.cpp
@@ -0,0 +1,52 @@
+///-------------------------------------------------------------------------------------------------
+///
+/// \file TactileMenu.cpp
+/// \brief Definitions for class TactileMenu
+/// \author Tobias Baumann (TH Nuernberg).
+/// \version 1.0.
+/// \date Mon Feb 10 17:11:34 2022.
+/// \copyright GNU Affero General Public License v3.0.
+///
+///-------------------------------------------------------------------------------------------------
+
+//includes
+#include "TactileMenu.h"
+
+
+namespace OpenViBE {
+namespace Plugins {
+namespace Tactilebci {
+
+//TactileMenu Memberfunctions
+TactileMenu::TactileMenu(int n_Tactilos)
+{
+ for(int i = 1; i <= n_Tactilos; i++)
+ {
+ m_LabelText.push_back("Tactilo" + std::to_string(i));
+ m_SubMenu.push_back(nullptr);
+ }
+}
+
+void TactileMenu::set_LabelText(int i, std::string Text)
+{
+ m_LabelText[i] = Text;
+}
+
+void TactileMenu::set_SubMenu(int i, TactileMenu* Menu)
+{
+ m_SubMenu[i] = Menu;
+}
+
+std::string TactileMenu::get_LabelText(int i)
+{
+ return(m_LabelText[i]);
+}
+
+TactileMenu* TactileMenu::get_SubMenu(int i)
+{
+ return(m_SubMenu[i]);
+}
+
+} // namespace Tactilebci
+} // namespace Plugins
+} // namespace OpenViBE
\ No newline at end of file
diff --git a/src/TactileVisualization/TactileMenu.h b/src/TactileVisualization/TactileMenu.h
new file mode 100644
index 0000000..3f0712d
--- /dev/null
+++ b/src/TactileVisualization/TactileMenu.h
@@ -0,0 +1,46 @@
+///-------------------------------------------------------------------------------------------------
+///
+/// \file TactileMenu.h
+/// \brief Class for the Menues of the Tactile P300 System
+/// \author Tobias Baumann (TH Nuernberg).
+/// \version 1.0.
+/// \date Mon Feb 10 17:10:32 2022.
+/// \copyright GNU Affero General Public License v3.0.
+///
+///-------------------------------------------------------------------------------------------------
+//includes
+#pragma once
+
+#include "../ovp_defines.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+namespace OpenViBE {
+namespace Plugins {
+namespace Tactilebci {
+
+//Class TactileMenu
+class TactileMenu
+{
+ private:
+ std::vector m_LabelText;
+ std::vector m_SubMenu;
+
+ public:
+ TactileMenu(int n_Tactilos);
+
+ std::string get_LabelText(int i);
+ TactileMenu* get_SubMenu(int i);
+
+ void set_LabelText(int i, std::string Text);
+ void set_SubMenu(int i, TactileMenu* Menu);
+};
+
+} // namespace Tactilebci
+} // namespace Plugins
+} // namespace OpenViBE
\ No newline at end of file
diff --git a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp
new file mode 100644
index 0000000..2dda5a7
--- /dev/null
+++ b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp
@@ -0,0 +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)
+ {
+ //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(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
diff --git a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.h b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.h
new file mode 100644
index 0000000..0cff75b
--- /dev/null
+++ b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.h
@@ -0,0 +1,162 @@
+///-------------------------------------------------------------------------------------------------
+///
+/// \file CBoxAlgorithmP300TactileVisualization.h
+/// \brief Classes of the Box P300TactileVisualization.
+/// \author Tobias Baumann (TH Nuernberg).
+/// \version 1.0.
+/// \date Sat May 07 14:20:29 2022.
+/// \copyright GNU Affero General Public License v3.0.
+///
+///-------------------------------------------------------------------------------------------------
+#pragma once
+
+//You may have to change this path to match your folder organisation
+#include "../ovp_defines.h"
+#include "TactileMenu.h"
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include