Problems with ModularEEG Data aquisition

Obtaining data from various hardware devices
Chris Veigl
Posts: 6
Joined: Wed Jul 15, 2009 10:43 pm

Re: Problems with ModularEEG Data aquisition

Post by Chris Veigl »

Hello all,

good to hear that there is some progress on that issue.

To clear up the (non-)existance of a "start button" :
i am using the monolithEEG
http://freenet-homepage.de/moosec/proje ... age431.htm
which is compatbile to the ModularEEG in terms of transmission protocol (P2) but has a start/pause button
and a USB converter onboard. when you plug in this device, a virual COM port is created, but the transfers
is not active unless you press the button.

this is the reason why i suspected that the timeout error is related to the fact that the data transfer starts immediately
when a ModularEEG is plugged in (the RS232-buffers will be full/overflowed if the readout does not start immediately).

regards,
chris.

nbaron
Posts: 23
Joined: Mon Jan 18, 2010 4:54 am

Re: Problems with ModularEEG Data aquisition

Post by nbaron »

I am currently working on my own version of monolithEEG, so I study the schemes and firmware of both monolithEEG and modEEG.
modEEG does not have a switch (even internally and not implemented by seller, in the orginal circuit had provided one), so perhaps you can try that :
1) Connect modEEG (with power off) to PC
2) Start Acq Server and OpenVibe, without press play or connect
3) Now the tricky part, in that order and as quickly as possible : turn on modEEG, press connect, press play.

:? This is not convenient but it willl to identify the problem, If as Chris Veigl said it is a buffer problem.
I hope this can help.

lbonnet
Site Admin
Posts: 417
Joined: Wed Oct 07, 2009 12:11 pm

Re: Problems with ModularEEG Data aquisition

Post by lbonnet »

The following posts have been moved to another dedicated topic, here.

Please create new topic for new question !

- The OpenViBE Team
Follow us on twitter >> openvibebci

Checkout my (old) blog for some OpenViBE tips & tricks : here !

mswynghedauw
Posts: 13
Joined: Thu Sep 10, 2009 8:44 am

Re: Problems with ModularEEG Data aquisition

Post by mswynghedauw »

Hi all

i had the same trouble with the current driver for the ModularEEG P2 in the last 2 release. maybe related to windows, i dont know.
anyway i rewrote the driver (taking example on brainbay) and it work fine for me now. here is the codes (C++) , maybe (if its validated by a majority) could it be included into the next version

marc

Code: Select all

#include "ovasCDriverModularEeg.h"
#include "../ovasCConfigurationGlade.h"

#include <openvibe-toolkit/ovtk_all.h>

#include <system/Time.h>
#include <math.h>
#include <iostream>

#if defined OVAS_OS_Windows
 #include <windows.h>
 #include <winbase.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <commctrl.h>
 #define TERM_SPEED 57600 

#else
 #include <stdio.h> 
 #include <unistd.h> 
 #include <fcntl.h> 
 #include <termios.h> 
 #include <sys/select.h> 
 #define TERM_SPEED B57600
#endif

// ModularEEG P2 drive for Windows 7   (Marc Swynghedauw) 2009

using namespace OpenViBEAcquisitionServer;
using namespace OpenViBE;
using namespace std;

//___________________________________________________________________//
//                                                                   //


void CDriverModularEeg::logPacket(void)
{
   uint32 ui32I;

   printf("\nPacket %d received:\n",m_ui8PacketNumber); 
   for (ui32I=0;ui32I<6;ui32I++)
   {
      printf("Channel %d:%d\n",ui32I+1,m_i32ChannelBuffer[ui32I]); 
   }
}
uint32 CDriverModularEeg::parseByteP2(int32   PacketsProcessed, uint8 ui8Actbyte)
{
	switch (m_ui16Readstate) 
	{
		  case 0: if (ui8Actbyte==165) 
			  {
				m_ui16Readstate++;
			  } else 
			  {
				m_ui16Readstate=0;
				PacketError=true;
			  }
		          break; 

		  case 1: if (ui8Actbyte==90)
			  {
				m_ui16Readstate++; 
			  }
			  else 
			  {
				m_ui16Readstate=0;
				PacketError=true;
			  }
			  break;

		  case 2: m_ui16Readstate++; 
			  m_ui8ModularVersion=  ui8Actbyte;
			  if (m_ui8ModularVersion!=2) {
				m_ui16Readstate=0;
				PacketError=true;
			  }
			  break;

          case 3: m_ui8PacketNumber = ui8Actbyte;
			  m_ui16ExtractPosition=0;
			  m_ui16Readstate++;
			  break;

		  case 4: if (m_ui16ExtractPosition < 12)
		  	  {   
                if ((m_ui16ExtractPosition & 1) == 0)
				{
					m_i32ChannelBuffer[m_ui16ExtractPosition>>1]= ((int32)ui8Actbyte)<<8;
				}
				else 
				{
					m_i32ChannelBuffer[m_ui16ExtractPosition>>1]+=ui8Actbyte;
				}
			     m_ui16ExtractPosition++;
			  }
			  else
			  {  
				m_ui16Switches= ui8Actbyte;
				m_ui16Readstate=0;
				for(uint32 j=0; j<m_oHeader.getChannelCount(); j++)
				{
					m_pSample[j*m_ui32SampleCountPerSentBlock+PacketsProcessed]=(float32)m_i32ChannelBuffer[j]-512;
				}			
				//logPacket();
		  	    return true;
			  }
			  break;

		  default: 
			  m_ui16Readstate=0;
	}		
	return false;
}


uint32 CDriverModularEeg::initTty(FD_TYPE * pFileDescriptor, uint32 ui32TtyNumber)
{
	uint8 l_ttyname[20];

#if defined OVAS_OS_Windows
	sprintf((char *)l_ttyname,"%s%d","\\\\.\\COM",ui32TtyNumber);
	DCB dcb = {0};
	*pFileDescriptor = CreateFile((LPCSTR) l_ttyname,GENERIC_READ | GENERIC_WRITE, 
                  0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

	if (*pFileDescriptor == INVALID_HANDLE_VALUE) 
	{
		printf("Could not open Communication Port %s for ModulerEEG Driver.\n",(char *) l_ttyname);
		return false;
	}
    
	if (!GetCommState(*pFileDescriptor, &dcb))      // get current DCB settings
	{ 
		return false; 
	}

    // update DCB rate, byte size, parity, and stop bits size
	dcb.DCBlength = sizeof(dcb);
	dcb.BaudRate = CBR_57600; //TERM_SPEED;
	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(*pFileDescriptor, &dcb);
	SetupComm(*pFileDescriptor, 1024, 1024);
	EscapeCommFunction(*pFileDescriptor, SETDTR);
	SetCommMask (*pFileDescriptor, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
    
#else
	struct termios l_terminalAttributes; 
     
	// open ttyS<i> for i < 10, else open ttyUSB<i-10>
	if (ui32TtyNumber<10)
	{
		sprintf((char *)l_ttyname,"%s%d","/dev/ttyS",ui32TtyNumber);
	}
	else
	{
		sprintf((char *)l_ttyname,"%s%d","/dev/ttyUSB",ui32TtyNumber-10);
	}

	if ((*pFileDescriptor = open((const char *)l_ttyname, O_RDWR)) == -1)   
	{ 
		printf("Could not open Communication Port %s for ModulerEEG Driver.\n",(char *) l_ttyname);
		return false; 
	} 

	if (tcgetattr(*pFileDescriptor, &l_terminalAttributes) != 0) 
	{ 
		close (*pFileDescriptor);
		*pFileDescriptor=-1;
		perror("terminal: tcgetattr() failed"); 
		return false; 
	} 

	/*   term_attr.c_cflag = TERM_SPEED | CS8 | CRTSCTS | CLOCAL | CREAD; */
	l_terminalAttributes.c_cflag = TERM_SPEED | CS8 | CLOCAL | CREAD; 
	l_terminalAttributes.c_iflag = 0; 
	l_terminalAttributes.c_oflag = OPOST | ONLCR; 
	l_terminalAttributes.c_lflag = 0; 
	if (tcsetattr(*pFileDescriptor, TCSAFLUSH, &l_terminalAttributes) != 0) 
	{
		close(*pFileDescriptor);
		*pFileDescriptor=-1;
		perror("terminal: tcsetattr() failed"); 
		return false;
	}
#endif
	return true;
 }

void CDriverModularEeg::closeTty(FD_TYPE i32FileDescriptor)
{
#if defined OVAS_OS_Windows
	CloseHandle(i32FileDescriptor);
#else
	close (i32FileDescriptor);
#endif
}

int32 CDriverModularEeg::readPacketFromTty(FD_TYPE i32FileDescriptor)
{
	uint8   l_ui8ReadBuffer[100];
	uint32  l_ui32BytesProcessed;
	int32   l_i32PacketsProcessed;

	l_i32PacketsProcessed=0;
	l_ui32BytesProcessed=0;

#if defined OVAS_OS_Windows
	uint32 l_ui32ReadLength; 
	uint32 l_ui32ReadOk;
	struct _COMSTAT l_status;
	uint32 l_ui32etat;

     
	l_ui32ReadLength = 0;
	l_ui32ReadOk=0;

	if (ClearCommError(i32FileDescriptor, (LPDWORD)&l_ui32etat, &l_status))
	{
		l_ui32ReadLength = l_status.cbInQue;
	}   
	for (l_ui32BytesProcessed=0; l_ui32BytesProcessed < l_ui32ReadLength; l_ui32BytesProcessed++)
	{
		// Read the data from the serial port.
		ReadFile (i32FileDescriptor, l_ui8ReadBuffer, 1, (LPDWORD)&l_ui32ReadOk, 0);
		if (l_ui32ReadOk==1)
		{
			if (parseByteP2(l_i32PacketsProcessed, l_ui8ReadBuffer[0]))
			{ 
			   l_i32PacketsProcessed++;
			}
		}
	 }

#else
	fd_set  l_inputFileDescriptorSet;
	struct timeval l_timeout;
	ssize_t l_ui32ReadLength=0; 
   
	l_timeout.tv_sec=1;
	l_timeout.tv_usec=0;

	FD_ZERO(&l_inputFileDescriptorSet); 
	FD_SET(i32FileDescriptor, &l_inputFileDescriptorSet); 

	switch (select(i32FileDescriptor+1, &l_inputFileDescriptorSet, NULL, NULL, &l_timeout)) 
	{
 		case -1: // error or timeoutASQAVWQ<QSDFG 
		case  0: return (-1);

		default:
			if (FD_ISSET(i32FileDescriptor, &l_inputFileDescriptorSet)) 
			{ 
				if ((l_ui32ReadLength = read(i32FileDescriptor, l_ui8ReadBuffer, 1)) > 0) 
				{ 
					for (l_ui32BytesProcessed=0; l_ui32BytesProcessed < l_ui32ReadLength; l_ui32BytesProcessed++)
					{
						if (parseByteP2(l_ui8ReadBuffer[l_ui32BytesProcessed]))
						{ 
						  l_i32PacketsProcessed++;
						} QRcfxdq<qwDFDWQ²HBCVXDQw<gcxcfdsw<²	
					}
 				}
			}
	}
#endif
	return(l_i32PacketsProcessed);
 }





//___________________________________________________________________//
//                                                                   //

CDriverModularEeg::CDriverModularEeg(IDriverContext& rDriverContext)
	:IDriver(rDriverContext)
	,m_pCallback(NULL)
	,m_bInitialized(false)
	,m_bStarted(false)
	,m_ui32SampleCountPerSentBlock(0)
	,m_pSample(NULL)
	,m_ui32TotalSampleCount(0)
	,m_ui32StartTime(0)
{
	m_oHeader.setExperimentIdentifier(4);
	m_oHeader.setSamplingFrequency(256);
	m_oHeader.setChannelCount(6);
}

void CDriverModularEeg::release(void)
{
	delete this;
}

const char* CDriverModularEeg::getName(void)
{
	return "Modular EEG P2";
}

//___________________________________________________________________//
//                                                                   //

OpenViBE::boolean CDriverModularEeg::initialize(
	const uint32 ui32SampleCountPerSentBlock,
	IDriverCallback& rCallback)
{
	if(m_bInitialized)
	{
		return false;
	}

	if(!m_oHeader.isChannelCountSet()
	 ||!m_oHeader.isSamplingFrequencySet())
	{
		return false;
	}


	m_ui16Readstate=0; 
	m_ui16ExtractPosition=0;

	if (!initTty(&m_i32FileDescriptor,	m_oHeader.getExperimentIdentifier()))
	{  
		return false;
	}

	m_pSample=new float32[m_oHeader.getChannelCount()*ui32SampleCountPerSentBlock];
	if(!m_pSample)
	{
		delete [] m_pSample;
		m_pSample=NULL;
		return false;
	}

	m_pCallback=&rCallback;
	m_bInitialized=true;
	m_ui32SampleCountPerSentBlock=ui32SampleCountPerSentBlock;
	m_ui32TotalSampleCount=0;
	m_ui8LastPacketNumber=0;

	printf("ModulerEEG Device Driver initialized.\n");
	m_ui32StartTime=System::Time::getTime();
	return true;
}

OpenViBE::boolean CDriverModularEeg::start(void)
{
	if(!m_bInitialized)
	{
		return false;
	}

	if(m_bStarted)
	{
		return false;
	}

	printf("ModulerEEG Device Driver started.\n");
	indexBuffer=-1;
	dwBytesTransferred=0;
	m_bStarted=true; 
	l_i32PacketsProcessed=0;
	isRunning=false;
	PacketError=false;
	return m_bStarted;
}

OpenViBE::boolean CDriverModularEeg::loop(void)
{
	if(!m_bInitialized)
	{
		return false;
	}

	if(!m_bStarted)
	{
		return false;
	}

//	uint32 l_ui32CurrentTime=System::Time::getTime();

	CStimulationSet l_oStimulationSet;
	l_oStimulationSet.setStimulationCount(1);
	l_oStimulationSet.setStimulationIdentifier(0, 0);
	l_oStimulationSet.setStimulationDate(0, 0);
	l_oStimulationSet.setStimulationDuration(0, 0);

	uint32  l_i32ReceivedSamples=0;
	
	uint32 l_ui32ReadLength; 
	uint32 l_ui32ReadOk;
	struct _COMSTAT l_status;
	//uint8   l_ui8ReadBuffer[100];
	uint32 l_ui32etat;
              // bytes actually read
	uint32 IndexStart;

	if (indexBuffer<=0) {
		if (ClearCommError(m_i32FileDescriptor, (LPDWORD)&l_ui32etat, &l_status))
		{
			dwBytesTransferred = l_status.cbInQue;
		} 
 		dwRead=0;
		l_oStimulationSet.setStimulationCount(0);
		if (dwBytesTransferred) {
			ReadFile (m_i32FileDescriptor, l_ui8ReadBuffer_New, dwBytesTransferred, &dwRead, 0);
			l_oStimulationSet.setStimulationCount(0);
			if (!isRunning) {
				printf("ModulerEEG Device Driver Receiving Data...\n");
				isRunning=true;
			}			
		} 

		IndexStart=0;
	} else {
		IndexStart=indexBuffer;
		l_oStimulationSet.setStimulationCount(0);
	}
	if (dwRead) {
			for (uint32 l_ui32BytesProcessed=IndexStart; l_ui32BytesProcessed < dwRead; l_ui32BytesProcessed++) 
			{				
				if (parseByteP2(l_i32PacketsProcessed, l_ui8ReadBuffer_New[l_ui32BytesProcessed]))
				{ 
				   l_i32PacketsProcessed++;
					m_ui8LastPacketNumber=m_ui8PacketNumber;

					if ( l_i32PacketsProcessed >= m_ui32SampleCountPerSentBlock) {
						m_ui32TotalSampleCount+=l_i32PacketsProcessed;
						l_oStimulationSet.setStimulationCount(0);
						if (PacketError)
							l_oStimulationSet.setStimulationCount(1);
						m_pCallback->setSamples(m_pSample);						
						m_pCallback->setStimulationSet(l_oStimulationSet);
						l_i32PacketsProcessed=0;
						//printf("Sending %d.........%d %d  start=%d pos=%d\n",m_ui32SampleCountPerSentBlock, dwRead, dwBytesTransferred, IndexStart , l_ui32BytesProcessed );
						indexBuffer=l_ui32BytesProcessed+1;
						PacketError=false;
						if (l_ui32BytesProcessed == dwRead-1)  {
							l_i32PacketsProcessed=0;
							indexBuffer=-1;
						}
						return true;
					} else {
						if (l_ui32BytesProcessed == dwRead-1)  {
						//	m_ui32TotalSampleCount+=l_i32PacketsProcessed;
							//m_pCallback->setSamples(m_pSample);							
							//m_pCallback->setStimulationSet(l_oStimulationSet);
						//	printf("1/ Sending smaller sample %d\n",l_i32PacketsProcessed);
							//l_i32PacketsProcessed=0;
							indexBuffer=-1;
							return true;	
						}
					}
				} else {

					if (l_ui32BytesProcessed == dwRead-1)  {
					//	m_ui32TotalSampleCount+=l_i32PacketsProcessed;
					//	printf("2/ Sending smaller sample %d\n",l_i32PacketsProcessed);
						//l_oStimulationSet.setStimulationCount(0);
						//m_pCallback->setSamples(m_pSample);
						//m_pCallback->setStimulationSet(l_oStimulationSet);
						//l_i32PacketsProcessed=0;
						indexBuffer=-1;
					}
				}

			}
				
	} 

	return true;
}


OpenViBE::boolean CDriverModularEeg::loop_old(void)
{
	if(!m_bInitialized)
	{
		return false;
	}

	if(!m_bStarted)
	{
		return false;
	}

//	uint32 l_ui32CurrentTime=System::Time::getTime();

	CStimulationSet l_oStimulationSet;
	l_oStimulationSet.setStimulationCount(1);
	l_oStimulationSet.setStimulationIdentifier(0, 0);
	l_oStimulationSet.setStimulationDate(0, 0);
	l_oStimulationSet.setStimulationDuration(0, 0);

	uint32  l_i32ReceivedSamples=0;
	int32 l_i32PacketsProcessed;

	while ( l_i32ReceivedSamples < m_ui32SampleCountPerSentBlock )
	{
       l_i32PacketsProcessed=readPacketFromTty(m_i32FileDescriptor);

	   switch (l_i32PacketsProcessed)
  		{ 
		case 0:     // no Packet finished
		  break;

 		case 1:    // Packet with Samples arrived
//			m_ui8LastPacketNumber++;
//			if (m_ui8LastPacketNumber != m_ui8PacketNumber)
//			printf("expected %d, received: %d\n",m_ui8LastPacketNumber,m_ui8PacketNumber);
			m_ui8LastPacketNumber=m_ui8PacketNumber;

			for(uint32 j=0; j<m_oHeader.getChannelCount(); j++)
			{
				m_pSample[j*m_ui32SampleCountPerSentBlock+l_i32ReceivedSamples]=(float32)m_i32ChannelBuffer[j]-512;
			}
			l_i32ReceivedSamples++;
			
			break;

		case -1:  // Timeout, could inidicate communication error
			return false;
	    } 
	}

	m_ui32TotalSampleCount+=m_ui32SampleCountPerSentBlock;
	printf("sending %d.\n", l_i32ReceivedSamples);
	m_pCallback->setSamples(m_pSample);
	m_pCallback->setStimulationSet(l_oStimulationSet);
	return true;
}

OpenViBE::boolean CDriverModularEeg::stop(void)
{
	if(!m_bInitialized)
	{
		return false;
	}

	if(!m_bStarted)
	{
		return false;
	}

	printf("ModulerEEG Device Driver stopped.\n");
	m_bStarted=false;
	isRunning=false;
	return !m_bStarted;
}

OpenViBE::boolean CDriverModularEeg::uninitialize(void)
{
	if(!m_bInitialized)
	{
		return false;
	}

	if(m_bStarted)
	{
		return false;
	}

	m_bInitialized=false;

	closeTty (m_i32FileDescriptor);
	printf("ModulerEEG Device Driver closed.\n");

	delete [] m_pSample;
	m_pSample=NULL;
	m_pCallback=NULL;

	return true;
}

//___________________________________________________________________//
//                                                                   //

OpenViBE::boolean CDriverModularEeg::isConfigurable(void)
{
	return true;
}

OpenViBE::boolean CDriverModularEeg::configure(void)
{
	CConfigurationGlade m_oConfiguration("../share/openvibe-applications/acquisition-server/interface-Modular-Eeg.glade");
	return m_oConfiguration.configure(m_oHeader);
}

lbonnet
Site Admin
Posts: 417
Joined: Wed Oct 07, 2009 12:11 pm

Re: Problems with ModularEEG Data aquisition

Post by lbonnet »

Warm thanks !
we will take a closer look at this driver as soon as possible.

If anyone has feedback to provide, feel free to post a comment !

Laurent
Follow us on twitter >> openvibebci

Checkout my (old) blog for some OpenViBE tips & tricks : here !

yrenard
Site Admin
Posts: 645
Joined: Fri Sep 01, 2006 3:39 pm
Contact:

Re: Problems with ModularEEG Data aquisition

Post by yrenard »

mswynghedauw wrote:Hi all

i had the same trouble with the current driver for the ModularEEG P2 in the last 2 release. maybe related to windows, i dont know.
anyway i rewrote the driver (taking example on brainbay) and it work fine for me now. here is the codes (C++) , maybe (if its validated by a majority) could it be included into the next version

marc
Dear mswynghedauw,

thank you for your contribution. the problem was a mix of the driver not being able to handle more than 1 P2 packet and Windows having a big buffer on COM ports. I quickly fixed that for students couple of weeks ago but did not have time to release it in the SVN. I will try to get best of the two implementations.

Thanks again,
Yann

Post Reply