MNE-CPP  beta 1.0
eegosportsdriver.cpp
Go to the documentation of this file.
1 //=============================================================================================================
37 //*************************************************************************************************************
38 //=============================================================================================================
39 // INCLUDES
40 //=============================================================================================================
41 
42 #include "eegosportsdriver.h"
43 #include "eegosportsproducer.h"
44 
45 
46 //*************************************************************************************************************
47 //=============================================================================================================
48 // USED NAMESPACES
49 //=============================================================================================================
50 
51 using namespace EEGoSportsPlugin;
52 
53 
54 //*************************************************************************************************************
55 //=============================================================================================================
56 // DEFINE MEMBER METHODS
57 //=============================================================================================================
58 
60 : m_pEEGoSportsProducer(pEEGoSportsProducer)
61 , m_bDllLoaded(true)
62 , m_bInitDeviceSuccess(false)
63 , m_uiNumberOfChannels(64)
64 , m_uiSamplingFrequency(1024)
65 , m_bUseChExponent(false)
66 , m_bWriteDriverDebugToFile(false)
67 , m_sOutputFilePath("/mne_x_plugins/resources/eegosports")
68 , m_bMeasureImpedances(false)
69 {
70  //Initialise NULL pointers
71  m_oLibHandle = NULL ;
72 
73  //Check which driver dll to take: TMSiSDK.dll oder TMSiSDK32bit.dll
74  #ifdef TAKE_EEGOSPORTSSDK_DLL //32 bit system & 64 bit (with 64 bit compiler)
75  m_oLibHandle = ::LoadLibrary(L"C:\\Windows\\System32\\eego.dll");
76  #elif TAKE_EEGOSPORTSSDK_32_DLL //64 bit (with 32 bit compiler)
77  m_oLibHandle = ::LoadLibrary(L"C:\\Windows\\SysWOW64\\eego.dll");
78  #endif
79 
80  //If dll can't be open return
81  if( m_oLibHandle == NULL)
82  {
83  cout << "Plugin EEGoSports - ERROR - Couldn't load DLL - Check if the driver for the TMSi USB Fiber Connector installed in the system dir" << endl;
84  m_bDllLoaded = false;
85  return;
86  }
87 
88  //Load DLL methods for initializing the driver
89  __load_dll_func__(m_oFpCreateAmplifier, CREATEAMPLIFIER, "CreateAmplifier");
90 
91  cout << "Plugin EEGoSports - INFO - EEGoSportsDriver() - Successfully loaded all DLL functions" << endl;
92 }
93 
94 
95 //*************************************************************************************************************
96 
98 {
99  //cout << "EEGoSportsDriver::~EEGoSportsDriver()" << endl;
100 }
101 
102 
103 //*************************************************************************************************************
104 
105 bool EEGoSportsDriver::initDevice(int iNumberOfChannels,
106  int iSamplingFrequency,
107  bool bUseChExponent,
108  bool bWriteDriverDebugToFile,
109  QString sOutpuFilePath,
110  bool bMeasureImpedance)
111 {
112  //Check if the driver DLL was loaded
113  if(!m_bDllLoaded)
114  return false;
115 
116  //Set global variables
117  m_uiNumberOfChannels = iNumberOfChannels;
118  m_uiSamplingFrequency = iSamplingFrequency;
119  m_bUseChExponent = bUseChExponent;
120  m_bWriteDriverDebugToFile = bWriteDriverDebugToFile;
121  m_sOutputFilePath = sOutpuFilePath;
122  m_bMeasureImpedances = bMeasureImpedance;
123 
124  //Open debug file to write to
125  if(m_bWriteDriverDebugToFile)
126  m_outputFileStream.open("mne_x_plugins/resources/eegosports/EEGoSports_Driver_Debug.txt", ios::trunc); //ios::trunc deletes old file data
127 
128  // Get device handler
129  HRESULT hres = (*m_oFpCreateAmplifier)(&m_pAmplifier);
130  if(FAILED(hres) || !m_pAmplifier)
131  {
132  cout << "Plugin EEGoSports - ERROR - Couldn't create amplifier! HRESULT: " << hres << endl;
133  return false;
134  }
135 
136  // Initialise device
137  HRESULT hr;
138  LPTSTR szDevString = NULL;
139 
140  // Get number and names of connected devices
141  UINT numDevices;
142  if(FAILED(m_pAmplifier->EnumDevices(&numDevices)))
143  {
144  cout << "Plugin EEGoSports - ERROR - Couldn't get device numbers!" << endl;
145  return false;
146  }
147 
148  // Get name of first connected device in the device list which is not a simulated device
149  for(UINT i = 0; i < numDevices; i++)
150  {
151  LPTSTR szName;
152  if(FAILED(m_pAmplifier->EnumDevices(i, &szName)))
153  {
154  cout << "Plugin EEGoSports - ERROR - Couldn't get device name!" << endl;
155  return false;
156  }
157 
158  // Make sure to get no simulation device. This should be no problem with later versions
159  QString temp;
160  temp = temp.fromWCharArray(szName);
161  if(!temp.contains("SIM"))
162  {
163  szDevString = szName;
164  break;
165  }
166 
167  delete szName;
168  }
169 
170  if( !szDevString )
171  {
172  cout << "Plugin EEGoSports - ERROR - No connected device found!" << endl;
173  return false;
174  }
175 
176  //cout<<"Found device: "<<szDevString<<endl;
177 
178  // Connect device - Make the USB handshake and setup internal states for communication with the hardware
179  if( FAILED(m_pAmplifier->Connect(szDevString)))
180  {
181  cout << "Plugin EEGoSports - ERROR - Connect call failed!" << endl;
182  return false;
183  }
184 
185  // This takes a while. Better wait
186  Sleep(100);
187 
188  // Reset device - Set it to a defined state
189  m_pAmplifier->Reset();
190 
191  // This takes a while. Better wait
192  Sleep(100);
193 
194  // reset the overcurrent protection
195  EEGO_CONFIG conf;
196  memset(&conf,0,sizeof(EEGO_CONFIG));
197  conf.BITS.bUnlockOCP = 1;
198  m_pAmplifier->SetConfig(conf);
199 
200  // This takes a while. Better wait
201  Sleep(100);
202 
203  // Set sampling frequency - Anything over 2kHZ is not supported and chances are high that they just don't work.
204  if(FAILED(m_pAmplifier->SetSamplingRate((EEGO_RATE)m_uiSamplingFrequency))) //(EEGO_RATE)m_uiSamplingFrequency EEGO_RATE_2048HZ
205  {
206  cout << "Plugin EEGoSports - ERROR - Can not set sampling frequency: " << m_uiSamplingFrequency << endl;
207  return false;
208  }
209 
210  // Set gain - use this with mV or set gain directly. Again, look into eego.h for acceptable values
211  EEGO_GAIN gain = GetGainForSignalRange(1000);
212 
213  // It is possible to set those for each individually. Again: not tested, not supported
214  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_A);
215  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_B);
216  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_C);
217  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_D);
218  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_E);
219  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_F);
220  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_G);
221  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_H);
222  m_pAmplifier->SetSignalGain(gain, EEGO_ADC_S);
223 
224  // We are measuring here so better leave the DAC off. Use it to create a rectangular test signal.
225 // hr = m_pAmplifier->SetDriverAmplitude(1000);
226 // hr |= m_pAmplifier->SetDriverPeriod(50);
227  hr = m_pAmplifier->SetDriverAmplitude(0);
228  hr |= m_pAmplifier->SetDriverPeriod(0);
229 
230  if(FAILED(hr))
231  return false;
232 
233  // This takes a while. Better wait
234  Sleep(100);
235 
236  // Get firmware version
237  USHORT firmwareVersion;
238  m_pAmplifier->GetFirmwareVersion(&firmwareVersion);
239 
240  //cout<<"Firmware version is: "<<firmwareVersion<<endl;
241 
242  // Start the sampling process
243  if(!m_pAmplifier)
244  return false;
245 
246  // You can get the set values from the device, too. We are using it here only for debug purposes
247  EEGO_RATE rate;
248 
249  m_pAmplifier->GetSamplingRate(&rate);
250  m_pAmplifier->GetSignalGain(&gain, EEGO_ADC_A);
251 
252  cout << "Starting Device with sampling rate: " << rate << "hz and a gain of: " << gain << "\n";
253 
254  // Always set device to idle first -> otherwise it could get confused
255  if(FAILED(m_pAmplifier->SetMode(EEGO_MODE_IDLE)))
256  return false;
257 
258  // With this call we tell the amplifier and driver stack to start streaming
259  if(FAILED(m_pAmplifier->SetMode(EEGO_MODE_STREAMING))) //EEGO_MODE_CALIBRATION EEGO_MODE_STREAMING EEGO_MODE_IMPEDANCE_CHA EEGO_MODE_IMPEDANCE_REF
260  return false;
261 
262  Sleep(100);
263 
264  cout << "Plugin EEGoSports - INFO - initDevice() - Successfully initialised the device. Starting Device with sampling rate: " << rate << "hz and a gain of: " << gain << endl;
265 
266  // Set flag for successfull initialisation true
267  m_bInitDeviceSuccess = true;
268 
269  return true;
270 }
271 
272 
273 //*************************************************************************************************************
274 
276 {
277  //Check if the device was initialised
278  if(!m_bInitDeviceSuccess)
279  {
280  cout << "Plugin EEGoSports - ERROR - uninitDevice() - Device was not initialised - therefore can not be uninitialised" << endl;
281  return false;
282  }
283 
284  //Check if the driver DLL was loaded
285  if(!m_bDllLoaded)
286  {
287  cout << "Plugin EEGoSports - ERROR - uninitDevice() - Driver DLL was not loaded" << endl;
288  return false;
289  }
290 
291  //Close the output stream/file
292  if(m_outputFileStream.is_open() && m_bWriteDriverDebugToFile)
293  {
294  m_outputFileStream.close();
295  m_outputFileStream.clear();
296  }
297 
298  // If global device handle is not defined return false
299  if(!m_pAmplifier)
300  return false;
301 
302  // Stop device sampling - Set device to idle mode
303  if(FAILED(m_pAmplifier->SetMode(EEGO_MODE_IDLE)))
304  return false;
305 
306  // Disconnect and release handle
307  m_pAmplifier->Disconnect();
308  m_pAmplifier->Release();
309 
310  //Reset to NULL pointers
311  m_pAmplifier = NULL;
312 
313  cout << "Plugin EEGoSports - INFO - uninitDevice() - Successfully uninitialised the device" << endl;
314  return true;
315 }
316 
317 
318 //*************************************************************************************************************
319 
320 bool EEGoSportsDriver::getSampleMatrixValue(MatrixXf& sampleMatrix)
321 {
322  //Check if device was initialised and connected correctly
323  if(!m_bInitDeviceSuccess)
324  {
325  cout << "Plugin EEGoSports - ERROR - getSampleMatrixValue() - Cannot start to get samples from device because device was not initialised correctly" << endl;
326  return false;
327  }
328 
329  // Init stuff
330  int channelMax = 0;
331  IBuffer* pBuffer; // The data storage
332 
333  //Fetch data from device/driver like this:
334  m_pAmplifier->GetData(&pBuffer);
335 
336  //Get sample and channel infos from device
337  m_uiNumberOfAvailableChannels = pBuffer->GetChannelCount();
338  int ulNumSamplesReceived = pBuffer->GetSampleCount();
339 
340  //Only do the next steps if there was at least one sample received, otherwise skip and wait until at least one sample was received
341  if(ulNumSamplesReceived>0)
342  {
343  //If the number of available channels is smaller than the number defined by the user -> set the channelMax to the smaller number
344  if(m_uiNumberOfAvailableChannels < m_uiNumberOfChannels)
345  channelMax = m_uiNumberOfAvailableChannels;
346  else
347  channelMax = m_uiNumberOfChannels;
348 
349  sampleMatrix = MatrixXf (channelMax, ulNumSamplesReceived);
350 
351  // Write data to matrix
352  for(int sample = 0; sample < ulNumSamplesReceived; sample++)
353  for(int channel = 0; channel < channelMax; channel++)
354  sampleMatrix(channel, sample) = m_bUseChExponent ? pBuffer->GetBuffer(channel, sample) * 1e-6 : pBuffer->GetBuffer(channel, sample);
355 
356  // Memory cleanup
357  pBuffer->Release();
358  pBuffer = NULL;
359 
360  if(m_outputFileStream.is_open() && m_bWriteDriverDebugToFile)
361  m_outputFileStream << "ulNumSamplesReceived: " << ulNumSamplesReceived << endl;
362 
363  return true;
364  }
365 
366  if(m_outputFileStream.is_open() && m_bWriteDriverDebugToFile)
367  m_outputFileStream << "ulNumSamplesReceived: " << ulNumSamplesReceived << endl;
368 
369  // Memory cleanup
370  pBuffer->Release();
371  pBuffer = NULL;
372 
373  return false;
374 
375 // //*************************************************************************************************************
376 // // Init stuff
377 // sampleMatrix.setZero(); // Clear matrix - set all elements to zero
378 // uint iSamplesWrittenToMatrix = 0;
379 // int channelMax = 0;
380 // int sampleMax = 0;
381 // int sampleIterator = 0;
382 
383 // //get samples from device until the complete matrix is filled, i.e. the samples per block size is met
384 // while(iSamplesWrittenToMatrix < m_uiSamplesPerBlock)
385 // {
386 // //Fetch data from device/driver like this:
387 // IBuffer* pBuffer; // The data storage
388 // m_pAmplifier->GetData(&pBuffer);
389 
390 // //Get sample and channel infos from device
391 // m_uiNumberOfAvailableChannels = pBuffer->GetChannelCount();
392 // int ulNumSamplesReceived = pBuffer->GetSampleCount();
393 
394 // //Only do the next steps if there was at least one sample received, otherwise skip and wait until at least one sample was received
395 // if(ulNumSamplesReceived > 0 || m_vSampleBlockBuffer.size()/m_uiNumberOfChannels > 0)
396 // {
397 // //cout<<"Sample received"<<endl;
398 // int actualSamplesWritten = 0; //Holds the number of samples which are actually written to the matrix in this while procedure
399 
400 // //If the number of available channels is smaller than the number defined by the user -> set the channelMax to the smaller number
401 // if(m_uiNumberOfAvailableChannels < m_uiNumberOfChannels)
402 // channelMax = m_uiNumberOfAvailableChannels;
403 // else
404 // channelMax = m_uiNumberOfChannels;
405 
406 // //Write the received samples to an extra buffer, so that they are not getting lost if too many samples were received. These are then written to the next matrix (block)
407 // for(int sample = 0; sample < ulNumSamplesReceived; sample++)
408 // for(int channel = 0; channel < channelMax; channel++)
409 // m_vSampleBlockBuffer.push_back(m_bUseChExponent ? pBuffer->GetBuffer(channel, sample) * 1e-6 : pBuffer->GetBuffer(channel, sample));
410 
411 // //Wieviele samples sollen in dieser while routine geschrieben werden
412 // //If the number of the samples which were already written to the matrix plus the last received number of samples is larger then the defined block size
413 // //-> only fill until the matrix is completeley filled with samples. The other (unused) samples are still stored in the vector buffer m_vSampleBlockBuffer and will be used in the next matrix which is to be sent to the circular buffer
414 // if(ulNumSamplesReceived > 0)
415 // {
416 // if(iSamplesWrittenToMatrix + ulNumSamplesReceived > m_uiSamplesPerBlock) // Too many samples received -> matrix would be too small
417 // sampleMax = m_uiSamplesPerBlock - iSamplesWrittenToMatrix + sampleIterator;
418 // else
419 // sampleMax = ulNumSamplesReceived + sampleIterator;
420 // }
421 // else // m_vSampleBlockBuffer.size()/m_uiNumberOfChannels > 0 and ulNumSamplesReceived < 0
422 // {
423 // if(iSamplesWrittenToMatrix + m_vSampleBlockBuffer.size()/m_uiNumberOfChannels > m_uiSamplesPerBlock)
424 // sampleMax = m_uiSamplesPerBlock - iSamplesWrittenToMatrix + sampleIterator;
425 // else
426 // sampleMax = m_vSampleBlockBuffer.size()/m_uiNumberOfChannels + sampleIterator;
427 // }
428 
429 // //Read the needed number of samples from the vector buffer to store them in the matrix
430 // for(; sampleIterator < sampleMax; sampleIterator++)
431 // {
432 // for(int channelIterator = 0; channelIterator < channelMax; channelIterator++)
433 // {
434 // sampleMatrix(channelIterator, sampleIterator) = m_vSampleBlockBuffer.first();
435 // m_vSampleBlockBuffer.pop_front();
436 // }
437 
438 // actualSamplesWritten ++;
439 // }
440 
441 // iSamplesWrittenToMatrix = iSamplesWrittenToMatrix + actualSamplesWritten;
442 // }
443 
444 // // Memory cleanup
445 // pBuffer->Release();
446 // pBuffer = NULL;
447 
448 // if(m_outputFileStream.is_open() && m_bWriteDriverDebugToFile)
449 // {
450 // m_outputFileStream << "samples in buffer: " << m_vSampleBlockBuffer.size()/m_uiNumberOfChannels << endl;
451 // m_outputFileStream << "ulNumSamplesReceived: " << ulNumSamplesReceived << endl;
452 // m_outputFileStream << "sampleMax: " << sampleMax << endl;
453 // m_outputFileStream << "sampleIterator: " << sampleIterator << endl;
454 // m_outputFileStream << "iSamplesWrittenToMatrix: " << iSamplesWrittenToMatrix << endl << endl;
455 // }
456 // }
457 
458 // return true;
459 
460  // //*************************************************************************************************************
461  // // Open Vibe solution
462  // sampleMatrix = MatrixXf::Zero(m_uiNumberOfChannels, m_uiSamplesPerBlock);
463 
464  // // OpenVibe code
465  // HRESULT hr;
466 
467  // if(!m_pAmplifier)
468  // return false;
469 
470  // // Fetch data from device/driver like this:
471  // IBuffer* pBuffer; // The data storage
472  // if(FAILED(hr = m_pAmplifier->GetData(&pBuffer))) // Fill the storage with data. Data is delivered only once
473  // {
474  // cout << "Plugin EEGoSports - ERROR - Getting Data from device failed! HRESULT: " << hr << endl;
475  // return false;
476  // }
477 
478  // // copy data from IBuffer to whatever structure you like to have.
479  // UINT nAmountOfSamples = pBuffer->GetSampleCount();
480  // //cout << "nAmountOfSamples: " << nAmountOfSamples << endl;
481  // UINT nAmountOfChannels = pBuffer->GetChannelCount();
482  // //cout << "nAmountOfChannels: " << nAmountOfChannels << endl;
483 
484  // // The data is stored in µV, use this constant for conversion
485  // double dLSBToSi = 1e-6;
486 
487  // // calculate start of unwritten data;
488  // for(UINT sample = 0; sample < nAmountOfSamples; sample++)
489  // {
490  // for(UINT channel = 0; channel < nAmountOfChannels; channel++)
491  // {
492  // int lValue = pBuffer->GetBuffer(channel, sample);
493 
494  // float sample = float(m_bUseChExponent ? lValue * dLSBToSi : lValue); // Put the sample into whatever structure you want now.
495  // //cout << sample << " ";
496 
497  // // check for triggers
498  // if(channel == EEGO_CHANNEL_TRG)
499  // {
500  // const uint currentTriggers = (uint)(lValue);
501  // const uint currentNewTriggers = currentTriggers & ~m_nLastTriggerValue; // Calculate which bits are new
502  // m_nLastTriggerValue = currentTriggers; // Save value for next trigger detection
503 
504  // if(currentNewTriggers != 0)
505  // {
506  // // Yay a trigger! Use it however you want
507  // }
508  // }
509  // }
510  // }
511 
512  // // Memory cleanup
513  // pBuffer->Release();
514  // pBuffer = NULL;
515 
516  // return true;
517 }
518 
519 
520 //*************************************************************************************************************
521 
522 EEGoSportsPlugin::EEGO_GAIN EEGoSportsDriver::GetGainForSignalRange(int range)
523 {
524  cout<<range<<endl;
525  using namespace EEGoSportsPlugin;
526  double idealGain = 1800. / range; // 1800 == MAX RANGE with only 1X amplification
527  int realGain = 0; // The minimal gain
528 
529  if(EEGO_GAIN_1X <= idealGain && realGain <= EEGO_GAIN_1X)
530  realGain = EEGO_GAIN_1X;
531 
532  if(EEGO_GAIN_2X <= idealGain && realGain <= EEGO_GAIN_2X)
533  realGain = EEGO_GAIN_2X;
534 
535  if(EEGO_GAIN_3X <= idealGain && realGain <= EEGO_GAIN_3X)
536  realGain = EEGO_GAIN_3X;
537 
538  if(EEGO_GAIN_4X <= idealGain && realGain <= EEGO_GAIN_4X)
539  realGain = EEGO_GAIN_4X;
540 
541  if(EEGO_GAIN_6X <= idealGain && realGain <= EEGO_GAIN_6X)
542  realGain = EEGO_GAIN_6X;
543 
544  if(EEGO_GAIN_8X <= idealGain && realGain <= EEGO_GAIN_8X)
545  realGain = EEGO_GAIN_8X;
546 
547  if(EEGO_GAIN_12X <= idealGain && realGain <= EEGO_GAIN_12X)
548  realGain = EEGO_GAIN_12X;
549 
550  return (EEGO_GAIN)realGain;
551 }
The EEGProducer class provides a EEG data producer for a given sampling rate.
bool getSampleMatrixValue(MatrixXf &sampleMatrix)
bool initDevice(int iNumberOfChannels, int iSamplingFrequency, bool bUseChExponent, bool bWriteDriverDebugToFile, QString sOutpuFilePath, bool bMeasureImpedance)
Contains the declaration of the EEGoSportsDriver class. This class implements the basic communication...
EEGoSportsDriver(EEGoSportsProducer *pEEGoSportsProducer)
Contains the declaration of the EEGoSportsProducer class.