This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,68 @@
/*
* \author Christoph Veigl, Yann Renard
*
* \copyright AGPL3
*
*/
#include "ovasCConfigurationOpenEEGModularEEG.h"
#include <sstream>
namespace OpenViBE {
namespace AcquisitionServer {
CConfigurationOpenEEGModularEEG::CConfigurationOpenEEGModularEEG(const char* gtkBuilderFilename, uint32_t& usbIdx)
: CConfigurationBuilder(gtkBuilderFilename), m_usbIdx(usbIdx) { m_listStore = gtk_list_store_new(1, G_TYPE_STRING); }
CConfigurationOpenEEGModularEEG::~CConfigurationOpenEEGModularEEG() { g_object_unref(m_listStore); }
bool CConfigurationOpenEEGModularEEG::preConfigure()
{
if (!CConfigurationBuilder::preConfigure()) { return false; }
GtkComboBox* box = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_device"));
g_object_unref(m_listStore);
m_listStore = gtk_list_store_new(1, G_TYPE_STRING);
gtk_combo_box_set_model(box, GTK_TREE_MODEL(m_listStore));
bool selected = false;
for (uint32_t i = 1; i < 17; ++i)
{
std::stringstream ss;
#if defined TARGET_OS_Windows
ss << "\\\\.\\COM" << i;
#elif defined TARGET_OS_Linux
if(i<10) { ss <<"/dev/ttyS" << i; }
else { ss << "/dev/ttyUSB%d"<< i-10; }
#endif
gtk_combo_box_append_text(box, ss.str().c_str());
if (m_usbIdx == i)
{
gtk_combo_box_set_active(box, i - 1);
selected = true;
}
}
if (!selected) { gtk_combo_box_set_active(box, 0); }
return true;
}
bool CConfigurationOpenEEGModularEEG::postConfigure()
{
GtkComboBox* box = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_device"));
if (m_applyConfig)
{
const int usbIndex = gtk_combo_box_get_active(box);
if (usbIndex >= 0) { m_usbIdx = uint32_t(usbIndex) + 1; }
}
if (!CConfigurationBuilder::postConfigure()) { return false; }
return true;
}
} // namespace AcquisitionServer
} // namespace OpenViBE
@@ -0,0 +1,29 @@
/*
* \author Christoph Veigl, Yann Renard
*
* \copyright AGPL3
*
*/
#pragma once
#include "../ovasCConfigurationBuilder.h"
#include <gtk/gtk.h>
namespace OpenViBE {
namespace AcquisitionServer {
class CConfigurationOpenEEGModularEEG final : public CConfigurationBuilder
{
public:
CConfigurationOpenEEGModularEEG(const char* gtkBuilderFilename, uint32_t& usbIdx);
~CConfigurationOpenEEGModularEEG() override;
bool preConfigure() override;
bool postConfigure() override;
protected:
uint32_t& m_usbIdx;
GtkListStore* m_listStore = nullptr;
};
} // namespace AcquisitionServer
} // namespace OpenViBE
@@ -0,0 +1,359 @@
/*
* \author Christoph Veigl, Yann Renard
*
* \copyright AGPL3
*
*/
#include "ovasCDriverOpenEEGModularEEG.h"
#include "ovasCConfigurationOpenEEGModularEEG.h"
#include <toolkit/ovtk_all.h>
#include <iostream>
#if defined TARGET_OS_Windows
#include <windows.h>
#include <winbase.h>
#include <cstdio>
#include <commctrl.h>
#define TERM_SPEED 57600
#elif defined TARGET_OS_Linux
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#define TERM_SPEED B57600
#else
#endif
namespace OpenViBE {
namespace AcquisitionServer {
CDriverOpenEEGModularEEG::CDriverOpenEEGModularEEG(IDriverContext& ctx)
: IDriver(ctx), m_settings("AcquisitionServer_Driver_OpenEEG-ModularEEG", m_driverCtx.getConfigurationManager())
{
m_header.setSamplingFrequency(256);
m_header.setChannelCount(m_nChannel);
m_settings.add("Header", &m_header);
m_settings.add("DeviceIdentifier", &m_deviceID);
m_settings.load();
}
//___________________________________________________________________//
// //
bool CDriverOpenEEGModularEEG::initialize(const uint32_t /*nSamplePerSentBlock*/, IDriverCallback& callback)
{
if (m_driverCtx.isConnected() || !m_header.isChannelCountSet() || !m_header.isSamplingFrequencySet()) { return false; }
m_readState = 0;
m_extractPos = 0;
if (!this->initTTY(&m_fileDesc, m_deviceID != uint32_t(-1) ? m_deviceID : 1)) { return false; }
m_sample = new float[m_header.getChannelCount()];
if (!m_sample)
{
delete [] m_sample;
m_sample = nullptr;
return false;
}
m_channelBuffers2.resize(6);
m_callback = &callback;
m_nChannel = m_header.getChannelCount();
m_lastPacketNumber = 0;
m_driverCtx.getLogManager() << Kernel::LogLevel_Debug << this->getName() << " driver initialized.\n";
return true;
}
bool CDriverOpenEEGModularEEG::start()
{
if (!m_driverCtx.isConnected() || m_driverCtx.isStarted()) { return false; }
m_driverCtx.getLogManager() << Kernel::LogLevel_Debug << this->getName() << " driver started.\n";
return true;
}
bool CDriverOpenEEGModularEEG::loop()
{
if (!m_driverCtx.isConnected()) { return false; }
if (this->readPacketFromTTY(m_fileDesc) < 0)
{
m_driverCtx.getLogManager() << Kernel::LogLevel_ImportantWarning << "Could not receive data from " << m_ttyName << "\n";
return false;
}
if (!m_channelBuffers.empty())
{
if (m_driverCtx.isStarted())
{
for (size_t i = 0; i < m_channelBuffers.size(); ++i)
{
for (uint32_t j = 0; j < m_nChannel; ++j) { m_sample[j] = float(m_channelBuffers[i][j]) - 512.0F; }
m_callback->setSamples(m_sample, 1);
}
m_driverCtx.correctDriftSampleCount(m_driverCtx.getSuggestedDriftCorrectionSampleCount());
}
m_channelBuffers.clear();
}
return true;
}
bool CDriverOpenEEGModularEEG::stop()
{
if (!m_driverCtx.isConnected() || !m_driverCtx.isStarted()) { return false; }
m_driverCtx.getLogManager() << Kernel::LogLevel_Debug << CString(this->getName()) << " driver stopped.\n";
return true;
}
bool CDriverOpenEEGModularEEG::uninitialize()
{
if (!m_driverCtx.isConnected() || m_driverCtx.isStarted()) { return false; }
this->closeTTY(m_fileDesc);
m_driverCtx.getLogManager() << Kernel::LogLevel_Debug << CString(this->getName()) << " driver closed.\n";
delete [] m_sample;
m_sample = nullptr;
m_callback = nullptr;
return true;
}
//___________________________________________________________________//
// //
bool CDriverOpenEEGModularEEG::configure()
{
CConfigurationOpenEEGModularEEG config(Directories::getDataDir() + "/applications/acquisition-server/interface-OpenEEG-ModularEEG.ui", m_deviceID);
if (!config.configure(m_header)) { return false; }
m_settings.save();
return true;
}
//___________________________________________________________________//
// //
bool CDriverOpenEEGModularEEG::parseByteP2(const uint8_t actbyte)
{
switch (m_readState)
{
case 0:
if (actbyte == 165) { m_readState++; }
break;
case 1:
if (actbyte == 90) { m_readState++; }
else { m_readState = 0; }
break;
case 2:
m_readState++;
break;
case 3:
m_packetNumber = actbyte;
m_extractPos = 0;
m_readState++;
break;
case 4:
if (m_extractPos < 12)
{
if ((m_extractPos & 1) == 0) { if (uint32_t(m_extractPos >> 1) < m_nChannel) { m_channelBuffers2[m_extractPos >> 1] = int(actbyte) << 8; } }
else { if (uint32_t(m_extractPos >> 1) < m_nChannel) { m_channelBuffers2[m_extractPos >> 1] += actbyte; } }
m_extractPos++;
}
else
{
m_channelBuffers.push_back(m_channelBuffers2);
m_switches = actbyte;
m_readState = 0;
return true;
}
break;
default: m_readState = 0;
break;
}
return false;
}
bool CDriverOpenEEGModularEEG::initTTY(FD_TYPE* descriptor, const uint32_t ttyNumber)
{
char ttyName[1024];
#if defined TARGET_OS_Windows
sprintf(ttyName, "\\\\.\\COM%d", ttyNumber);
DCB dcb = { 0 };
*descriptor = ::CreateFile(LPCSTR(ttyName), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (*descriptor == INVALID_HANDLE_VALUE)
{
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "Could not open port [" << CString(ttyName) << "]\n";
return false;
}
if (!GetCommState(*descriptor, &dcb))
{
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "Could not get comm state on port [" << CString(ttyName) << "]\n";
return false;
}
// update DCB rate, byte size, parity, and stop bits size
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = CBR_56000;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.EvtChar = '\0';
// update flow control settings
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fTXContinueOnXoff = FALSE;
dcb.XonChar = 0;
dcb.XoffChar = 0;
dcb.XonLim = 0;
dcb.XoffLim = 0;
dcb.fParity = FALSE;
SetCommState(*descriptor, &dcb);
SetupComm(*descriptor, 64/*1024*/, 64/*1024*/);
EscapeCommFunction(*descriptor, SETDTR);
SetCommMask(*descriptor, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
#elif defined TARGET_OS_Linux
struct termios terminalAtt;
// open ttyS<i> for i < 10, else open ttyUSB<i-10>
if(ttyNumber<10) { ::sprintf(ttyName, "/dev/ttyS%d", ttyNumber); }
else { ::sprintf(ttyName, "/dev/ttyUSB%d", ttyNumber-10); }
if((*descriptor=::open(ttyName, O_RDWR))==-1)
{
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "Could not open port [" << CString(ttyName) << "]\n";
return false;
}
if(tcgetattr(*descriptor, &terminalAtt)!=0)
{
::close(*descriptor);
*descriptor=-1;
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "terminal: tcgetattr() failed - did you use the right port [" << CString(ttyName) << "] ?\n";
return false;
}
/* terminalAtt.c_cflag = TERM_SPEED | CS8 | CRTSCTS | CLOCAL | CREAD; */
terminalAtt.c_cflag = TERM_SPEED | CS8 | CLOCAL | CREAD;
terminalAtt.c_iflag = 0;
terminalAtt.c_oflag = OPOST | ONLCR;
terminalAtt.c_lflag = 0;
if(tcsetattr(*descriptor, TCSAFLUSH, &terminalAtt)!=0)
{
::close(*descriptor);
*descriptor=-1;
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "terminal: tcsetattr() failed - did you use the right port [" << CString(ttyName) << "] ?\n";
return false;
}
#else
return false;
#endif
m_ttyName = ttyName;
return true;
}
void CDriverOpenEEGModularEEG::closeTTY(const FD_TYPE fileDesc)
{
#if defined TARGET_OS_Windows
CloseHandle(fileDesc);
#elif defined TARGET_OS_Linux
::close(fileDesc);
#else
#endif
}
int CDriverOpenEEGModularEEG::readPacketFromTTY(const FD_TYPE fileDesc)
{
m_driverCtx.getLogManager() << Kernel::LogLevel_Debug << "Enters readPacketFromTTY\n";
uint8_t readBuffer[100];
int packetsProcessed = 0;
#if defined TARGET_OS_Windows
uint32_t readLength = 0;
uint32_t readOk = 0;
struct _COMSTAT status;
DWORD state;
if (ClearCommError(fileDesc, &state, &status)) { readLength = status.cbInQue; }
for (uint32_t i = 0; i < readLength; i++)
{
ReadFile(fileDesc, readBuffer, 1, LPDWORD(&readOk), nullptr);
if (readOk == 1) { if (this->parseByteP2(readBuffer[0])) { packetsProcessed++; } }
}
#elif defined TARGET_OS_Linux
fd_set inputFileDescSet;
struct timeval time;
size_t readLength=0;
bool finished=false;
time.tv_sec=0;
time.tv_usec=0;
do
{
FD_ZERO(&inputFileDescSet);
FD_SET(fileDesc, &inputFileDescSet);
switch(select(fileDesc+1, &inputFileDescSet, nullptr, nullptr, &time))
{
case -1: // error or timeout
case 0:
finished=true;
break;
default:
if(FD_ISSET(fileDesc, &inputFileDescSet))
{
if((readLength=::read(fileDesc, readBuffer, 1)) > 0)
{
for (uint32_t i = 0; i<readLength; i++) { if(this->parseByteP2(readBuffer[i])) { packetsProcessed++; } }
}
}
else { finished = true; }
break;
}
}
while(!finished);
#else
#endif
m_driverCtx.getLogManager() << Kernel::LogLevel_Debug << "Leaves readPacketFromTTY\n";
return packetsProcessed;
}
} // namespace AcquisitionServer
} // namespace OpenViBE
@@ -0,0 +1,79 @@
/*
* \author Christoph Veigl, Yann Renard
*
* \copyright AGPL3
*/
#pragma once
#include "ovasIDriver.h"
#include "../ovasCHeader.h"
#include "../ovasCSettingsHelper.h"
#include "../ovasCSettingsHelperOperators.h"
#if defined TARGET_OS_Windows
typedef void* FD_TYPE;
#elif defined TARGET_OS_Linux
typedef int FD_TYPE;
#else
#endif
#include <vector>
namespace OpenViBE {
namespace AcquisitionServer {
/**
* \class CDriverOpenEEGModularEEG
* \author Christoph Veigl, Yann Renard
*/
class CDriverOpenEEGModularEEG final : public IDriver
{
public:
explicit CDriverOpenEEGModularEEG(IDriverContext& ctx);
void release() { delete this; }
const char* getName() override { return "OpenEEG Modular EEG P2"; }
bool initialize(const uint32_t nSamplePerSentBlock, IDriverCallback& callback) override;
bool uninitialize() override;
bool start() override;
bool stop() override;
bool loop() override;
bool isConfigurable() override { return true; }
bool configure() override;
const IHeader* getHeader() override { return &m_header; }
protected:
// void logPacket();
bool parseByteP2(uint8_t actbyte);
bool initTTY(FD_TYPE* descriptor, uint32_t ttyNumber);
int readPacketFromTTY(FD_TYPE fileDesc);
static void closeTTY(FD_TYPE fileDesc);
SettingsHelper m_settings;
IDriverCallback* m_callback = nullptr;
CHeader m_header;
uint32_t m_nChannel = 6;
uint32_t m_deviceID = uint32_t(-1);
float* m_sample = nullptr;
FD_TYPE m_fileDesc;
uint16_t m_readState = 0;
uint16_t m_extractPos = 0;
uint8_t m_packetNumber = 0;
uint8_t m_lastPacketNumber = 0;
uint16_t m_switches = 0;
std::vector<std::vector<int>> m_channelBuffers;
std::vector<int> m_channelBuffers2;
CString m_ttyName;
};
} // namespace AcquisitionServer
} // namespace OpenViBE