P300 Output --> Serial Com Port

Forum for software developers to discuss BCI2000 software development
jjbaker
Posts: 9
Joined: 07 May 2008, 11:58

P300 Output --> Serial Com Port

Post by jjbaker » 07 May 2008, 12:22

I need to output the letters selected by the user in the P300 speller to a serial communications port.

Has anybody already done this?

If not, is it something as simple as modifying a few lines in a module? Where should I start?

Thanks in advance!

John

gschalk
Posts: 615
Joined: 28 Jan 2003, 12:37

P3Speller ...

Post by gschalk » 08 May 2008, 07:14

John,

The best way to do this may be to use the UDP-based protocol that is built into the P3Speller. Using this protocol, which can be enabled using the parameter DestinationAddress that is described on

http://www.bci2000.org/wiki/index.php/U ... pellerTask

you can write a little external program in any programming language that reads the characters from UDP and sends them to a serial port.

Of course, you may also modify the existing P3Speller code, but this would mean it would not directly take advantage of potential future improvements to the P3Speller that comes with BCI2000.

Gerwin

mellinger
Posts: 1341
Joined: 12 Feb 2003, 11:06

Post by mellinger » 08 May 2008, 07:41

John,

a program that redirects UDP input into serial output would be quite short, something along the following lines:

Code: Select all

#include "SockStream.h"
#include "SerialStream.h"

using namespace std;

int 
main( int, char** )
{
  receiving_udpsocket s( "localhost:5000" );
  sockstream input( s );
  serialstream output( "COM1" );
  string line;
  while( getline( input, line ) )
     output << line << endl;
  return 0;
}
Regards,
Jürgen
Last edited by mellinger on 14 May 2008, 14:03, edited 3 times in total.

jjbaker
Posts: 9
Joined: 07 May 2008, 11:58

Post by jjbaker » 14 May 2008, 11:30

Hi, thanks that worked perfectly. I had to do the following to get it to compile. I'm using the Dev-C++ IDE (http://www.bloodshed.net/dev/devcpp.html) which is freeware, open source and I think follows C++ standards pretty closely.

  • 1. Find SockStream.h/cpp and SerialStream.h/cpp, and add them to the project.
    • BCI2000 SVN Source Code\src\shared\utils
    2. Add libws2_32.a to the linker parameters
    • Project > Project Options > Parameters Tab > Add Library or Object
      C:/Dev-Cpp/lib/libws2_32.a

    3. Tell the compiler where to find the string type:

    Code: Select all

    std::string line;
Additionally, the P300 Speller automatically adds "P3Speller_Output " before the output character, and adds return characters after. Assuming your matrix only has letters, numbers and no special characters.

Code: Select all

output << line[17] << std::endl;
Will output just the character in question to your serial com port. I'd also suggest adding unix styled command line options for changing the host:port and com-port if you use Jürgen's code.

Thanks again!
John[/size]

mellinger
Posts: 1341
Joined: 12 Feb 2003, 11:06

Post by mellinger » 14 May 2008, 13:57

John,

thanks for your helpful feedback.
I added a line

Code: Select all

using namespace std;
to the example program above in order to fix the compilation problem.

Regards,
Juergen

jjbaker
Posts: 9
Joined: 07 May 2008, 11:58

Post by jjbaker » 19 May 2008, 13:05

Is there a function in SerialStream to read in the data coming in from the com port?

John

mellinger
Posts: 1341
Joined: 12 Feb 2003, 11:06

Post by mellinger » 19 May 2008, 13:49

John,

using the extractor (>>) rather than the inserter (<<), or getline(), should work for you:

Code: Select all

serialstream input( "COM1" );
// Read a name and a number separated by white space:
int number = 0;
string name;
input >> name >> number;
// Read to the next newline:
string line;
getline( input, line );
For more details about C++ iostreams, see http://www.parashift.com/c++-faq-lite/input-output.html, or a C++ textbook.

Regards,
Juergen
Last edited by mellinger on 22 May 2008, 12:24, edited 1 time in total.

jjbaker
Posts: 9
Joined: 07 May 2008, 11:58

Post by jjbaker » 21 May 2008, 14:28

I ended up using a different h/cpp for the serial communications. For some reason, whenever I tried to read the serial buffer with SerialStream.h/cpp, I'd get the first set of information but nothing after that. The getch()/break setup works in other similar programs but isn't working here for some reason but other than that, the program performs perfectly.

If you have any suggestions on the coding to make it shorter, more elegant, or more inline with professional programming style, I'm all ears as most C/C++ I've done in the past was personal or academic. I have comments in the official version but removed them here for conciseness.

Thanks again for all the help!

Code: Select all

u2s.cpp

/*	UDP to Serial (u2s.cpp)
	This program takes the UDP packets outputed by a host at specified port,
	parses them and redirects them to specified serial com port, it then reads
	the same com port for any returning information.*/

#include <conio.h>		
#include "comport.h"		
#include "SockStream.h"		

using namespace std;
int main(int argc, char *argv[])
{
	//////////////////////////// Intialize Variables ///////////////////////////
	
	int buffIn=8;				
	int buffOut=0;				
	char serIn[8]={'\0'};		
	char userInput='\0';		
	char baud[]="9600";		
	string line("");			
	string parsed("");			
	string hostIP("localhost"); 
	string hostPort("5000");	
	string host("");			
	string port="COM5";			
	int swNum=1;
    
	/////////////////////////// Command Line Parsing ///////////////////////////
	
	while ((swNum < argc) && (argv[swNum][0]=='-')) {
        string sw = argv[swNum];	
		if (sw=="-h"){			
			cout << "Usage: u2s -i <host> -p <port> -c <com port>\n";
			cout << "Example: u2s -i localhost -p 5000 -c 5\n";
			cout << "Omissions will use defaults: localhost:5000, COM5\n";
			system("PAUSE");
			return 1;
		}
		else if (sw=="-i") {		
            swNum++;				
            hostIP = argv[swNum];	
        }
        else if (sw=="-p") {		
            swNum++;			
            hostPort = argv[swNum];
        }
        else if (sw=="-c") {		
            swNum++;			
            port = argv[swNum];		
            port = "COM"+port;		
        }
        else						
            cout << "Unknown switch: " << argv[swNum] << endl;
        swNum++;					
    }
	host=hostIP+":"+hostPort;		
	
	///////////////////////////// Data Redirection /////////////////////////////

	if(!openComPort(port.c_str(),baud)){	
		cout << "Could not open " << port << '\n';
		system("PAUSE");
		return 1;							
	}
	receiving_udpsocket s( host.c_str() );			
	sockstream udpIn( s );						
	cout << "Redirecting traffic from "<< host << " to " << port << ".\n\n";
	while(1){
		if(getline(udpIn,line)){					
			parsed=line[17];					
			buffOut=parsed.length();				
			sendData(parsed.c_str(),buffOut);		
			cout << "U2S: " << parsed << endl;		
		}
		for(int i=0; i<buffIn; i++){				
			serIn[i]='\0';							
		}
		if(readData(serIn,buffIn))					
			cout << "S2U: " << serIn << endl;		
		if (kbhit()){								
			userInput = getch();					
			if (userInput == 27)					
				break;							
		}
	}
	closeComPort();									
	return 0;
} 												

The comport.h/cpp was posted here by Daniel Lundin from Stockholm, Sweden.

Code: Select all

comport.h

#ifndef _COMPORT_H
#define _COMPORT_H
#include <windows.h>
#include <string.h>

BOOL  openComPort  (const char* port, const char* baudrate);
void  closeComPort (void);
DWORD sendData     (const char* data, DWORD size);
DWORD receiveData  (char* data, DWORD size);

#endif /* _COMPORT_H */

Code: Select all

comport.c

#include "comport.h"
static HANDLE _hCom;

BOOL openComPort (const char* port, const char* baudrate){
  char buildStr[50];
  DCB dcb;       
  COMMTIMEOUTS timeouts = {0};
  _hCom = CreateFile(port,
                     GENERIC_READ | GENERIC_WRITE,
                     0,
                     0,
                     OPEN_EXISTING,
                     0,
                     0);
  if(_hCom == INVALID_HANDLE_VALUE)   {
    _hCom = NULL;
    return FALSE;
  }

  /* set timeouts */
  timeouts.ReadTotalTimeoutConstant    = 100;
  timeouts.ReadTotalTimeoutMultiplier  = 0;
  timeouts.WriteTotalTimeoutMultiplier = 0;
  timeouts.WriteTotalTimeoutConstant   = 0;
  if(SetCommTimeouts(_hCom, &timeouts) == FALSE)
    return FALSE;
  dcb.DCBlength = sizeof(DCB);
  if(GetCommState(_hCom, &dcb) == FALSE)
    return FALSE;

  /* Simplified way of setting up the COM port using strings: */
  buildStr[0] = '\0';
  strcat(buildStr, "baud=");
  strcat(buildStr, baudrate);
  strcat(buildStr," parity=N data=8 stop=1");

  /* (A more effective way is to setup the members of the DCB struct manually, 
     then you don't need BuildCommDCB) */
  BuildCommDCB(buildStr, &dcb);
  return SetCommState(_hCom, &dcb);
}  


void closeComPort(void){
  CloseHandle(_hCom);
}

DWORD sendData (const char* data, DWORD size){
  DWORD numberOfBytesWritten;
  WriteFile(_hCom,
            data,
            size,
            &numberOfBytesWritten,
            0);
  return numberOfBytesWritten;
}

DWORD receiveData (char* data, DWORD size){
  DWORD numberOfBytesRead;
  ReadFile(_hCom,
           data,
           size,
           &numberOfBytesRead,
           0);
  return numberOfBytesRead;
}

Gesanan
Posts: 5
Joined: 20 Jan 2009, 11:13

Post by Gesanan » 23 Jan 2009, 11:10

Hi.

When I try to compile this piece of code I got these Compilation Errors:

E2209: Unable to open include file 'SockStream.h"
E2209: Unable to open include file 'SockStream.h"

I've looked for and I don't have these files on my PC.

What can I do?

Thank you very much.

Gesanan
mellinger wrote:John,

a program that redirects UDP input into serial output would be quite short, something along the following lines:

Code: Select all

#include "SockStream.h"
#include "SerialStream.h"

using namespace std;

int 
main( int, char** )
{
  receiving_udpsocket s( "localhost:5000" );
  sockstream input( s );
  serialstream output( "COM1" );
  string line;
  while( getline( input, line ) )
     output << line << endl;
  return 0;
}
Regards,
Jürgen

jjbaker
Posts: 9
Joined: 07 May 2008, 11:58

Post by jjbaker » 23 Jan 2009, 11:40

It's available as part of the BCI2000 source code release:

BCI2000 SVN Source Code\src\shared\utils

Gesanan wrote:Hi.

When I try to compile this piece of code I got these Compilation Errors:

E2209: Unable to open include file 'SockStream.h"
E2209: Unable to open include file 'SockStream.h"

I've looked for and I don't have these files on my PC.

What can I do?

Thank you very much.

Gesanan
mellinger wrote:John,

a program that redirects UDP input into serial output would be quite short, something along the following lines:

Code: Select all

#include "SockStream.h"
#include "SerialStream.h"

using namespace std;

int 
main( int, char** )
{
  receiving_udpsocket s( "localhost:5000" );
  sockstream input( s );
  serialstream output( "COM1" );
  string line;
  while( getline( input, line ) )
     output << line << endl;
  return 0;
}
Regards,
Jürgen

Gesanan
Posts: 5
Joined: 20 Jan 2009, 11:13

Post by Gesanan » 23 Jan 2009, 12:18

Thank you very much. I've found SerialStream at:

root/tags/BCI2000.v1.4/src/shared

However I can't find SockStream.

Could somebody tell me where I could find it?

Thanks a lot.

Gemma
jjbaker wrote:It's available as part of the BCI2000 source code release:

BCI2000 SVN Source Code\src\shared\utils

Gesanan wrote:Hi.

When I try to compile this piece of code I got these Compilation Errors:

E2209: Unable to open include file 'SockStream.h"
E2209: Unable to open include file 'SockStream.h"

I've looked for and I don't have these files on my PC.

What can I do?

Thank you very much.

Gesanan
mellinger wrote:John,

a program that redirects UDP input into serial output would be quite short, something along the following lines:

Code: Select all

#include "SockStream.h"
#include "SerialStream.h"

using namespace std;

int 
main( int, char** )
{
  receiving_udpsocket s( "localhost:5000" );
  sockstream input( s );
  serialstream output( "COM1" );
  string line;
  while( getline( input, line ) )
     output << line << endl;
  return 0;
}
Regards,
Jürgen

mellinger
Posts: 1341
Joined: 12 Feb 2003, 11:06

Post by mellinger » 26 Jan 2009, 13:03

Gesanan,

the current BCI2000 source tree is under root/trunk.
There, the SerialStream and SockStream classes are below
src/shared/utils.

HTH,
Juergen

Gesanan
Posts: 5
Joined: 20 Jan 2009, 11:13

Post by Gesanan » 13 Feb 2009, 08:18

Hi all.

Before sending and receiving data to and from the serial port I need to configurate it with the next setings: no parity, no flowcontrol, 8 data bits, 9600 bps.

I've read at "SerialStream.h" that "Configuration of the serial interface is independent of stream communication, and not provided here. Configuration must take place before opening the interface from the serialstream class.".

Could somebody guide me about how to do it?

Thanks a lot.

Gemma

mellinger
Posts: 1341
Joined: 12 Feb 2003, 11:06

Post by mellinger » 13 Feb 2009, 09:08

Hi,

you will need to create a handle to the serial port by opening it, and then use the SetCommState/GetCommState functions from the Win32 API.

There is an example provided at:
http://msdn.microsoft.com/en-us/library ... S.85).aspx

HTH,
Juergen

Gesanan
Posts: 5
Joined: 20 Jan 2009, 11:13

Post by Gesanan » 25 Feb 2009, 09:51

mellinger wrote:John,

a program that redirects UDP input into serial output would be quite short, something along the following lines:

Code: Select all

#include "SockStream.h"
#include "SerialStream.h"

using namespace std;

int 
main( int, char** )
{
  receiving_udpsocket s( "localhost:5000" );
  sockstream input( s );
  serialstream output( "COM1" );
  string line;
  while( getline( input, line ) )
     output << line << endl;
  return 0;
}
Regards,
Jürgen
Hello everybody.

If I want to read an integer form the socket the code would be like this??

Code: Select all

int i;

receiving_udpsocket s( host.c_str() );
sockstream udpIn( s );
udpIn >> i;
cout << "\nReceived int: " << i;
Thanks a lot.

Gesanan

Locked

Who is online

Users browsing this forum: No registered users and 0 guests