#include "ofSerial.h"

static bool 	bInited;

#ifdef TARGET_WIN32
	static HANDLE  	hComm;		// the handle to the serial port pc
#else
	static int 		fd;			// the handle to the serial port mac
#endif



//----------------------------------------------------------------
void ofSerialSetup (string portName, int baud){


	bInited = false;

	//---------------------------------------------
	#ifdef TARGET_OSX
	//---------------------------------------------

	    struct termios toptions;

	    printf("ofSerialInit: opening port %s @ %d bps\n", portName.c_str(), baud);

		fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);

		if(fd == -1){
			printf("open: unable to open port");
		}

		struct termios options;
		tcgetattr(fd,&options);

		switch(baud){
		   case 300: 	cfsetispeed(&options,B300);
						cfsetospeed(&options,B300);
						break;
		   case 1200: 	cfsetispeed(&options,B1200);
						cfsetospeed(&options,B1200);
						break;		   
		   case 2400: 	cfsetispeed(&options,B2400);
						cfsetospeed(&options,B2400);
						break;		
		   case 4800: 	cfsetispeed(&options,B4800);
						cfsetospeed(&options,B4800);
						break;	
		   case 9600: 	cfsetispeed(&options,B9600);
						cfsetospeed(&options,B9600);
						break;
		   case 14400: 	cfsetispeed(&options,B14400);
						cfsetospeed(&options,B14400);
						break;						
		   case 19200: 	cfsetispeed(&options,B19200);
						cfsetospeed(&options,B19200);
						break;
		   case 28800: 	cfsetispeed(&options,B28800);
						cfsetospeed(&options,B28800);
						break;
		   case 38400: 	cfsetispeed(&options,B38400);
						cfsetospeed(&options,B38400);
						break;
		   case 57600:  cfsetispeed(&options,B57600);
						cfsetospeed(&options,B57600);
						break;		
		   case 115200: cfsetispeed(&options,B115200);
						cfsetospeed(&options,B115200);
						break;								
									
			default:	cfsetispeed(&options,B9600);
						cfsetospeed(&options,B9600);
						printf("ofSerialInit: cannot set %i baud setting baud to 9600\n", baud); 
						break;
		}

		options.c_cflag |= (CLOCAL | CREAD);
		options.c_cflag &= ~PARENB;
		options.c_cflag &= ~CSTOPB;
		options.c_cflag &= ~CSIZE;
		options.c_cflag |= CS8;
		tcsetattr(fd,TCSANOW,&options);

		bInited = true;
		printf("sucess in opening serial connection\n");

	    return;
	//---------------------------------------------
    #endif
    //---------------------------------------------


    //---------------------------------------------
	#ifdef TARGET_WIN32
	//---------------------------------------------

	// open the serial port:
	// "COM4", etc...

	hComm=CreateFileA(portName.c_str(),GENERIC_READ|GENERIC_WRITE,0,0,
					OPEN_EXISTING,0,0);

	if(hComm==INVALID_HANDLE_VALUE){
		printf("error opening port %s\n please check to see if it's in use, or the right port\n", portName);
		return;
	}

	// now try the settings:
	COMMCONFIG cfg;
	DWORD cfgSize;
	char  buf[80];
	
	cfgSize=sizeof(cfg);
	GetCommConfig(hComm,&cfg,&cfgSize);
	int bps = baud;
	sprintf(buf,"baud=%d parity=N data=8 stop=1",bps);
	
	// BuildCommDCB on visual studio seems to need this
	// because BuildCommDCB expects unicode input

	#if (_MSC_VER)       // microsoft visual studio
		wchar_t bufWide[80];
		mbstowcs(bufWide, buf, strlen(buf));	
		if(!BuildCommDCB(bufWide,&cfg.dcb)){
			printf("ofSerial: unable to build comm dcb; (%s) \n",buf);
		}
	#else
		if(!BuildCommDCB(buf,&cfg.dcb)){
			printf("Can't build comm dcb; %s",buf);
		}
	#endif

	
	// Set baudrate and bits etc.
	// Note that BuildCommDCB() clears XON/XOFF and hardware control by default
	
	if(!SetCommState(hComm,&cfg.dcb)){
		printf("Can't set comm state");
	}
	//printf(buf,"bps=%d, xio=%d/%d\n",cfg.dcb.BaudRate,cfg.dcb.fOutX,cfg.dcb.fInX);

	// Set communication timeouts (NT)
	COMMTIMEOUTS tOut;
	GetCommTimeouts(hComm,&tOut);
	// Make timeout so that:
	// - return immediately with buffered characters
	tOut.ReadIntervalTimeout=MAXDWORD;
	tOut.ReadTotalTimeoutMultiplier=0;
	tOut.ReadTotalTimeoutConstant=0;
	SetCommTimeouts(hComm,&tOut);

	bInited = true;

	//---------------------------------------------
	#endif
	//---------------------------------------------
}


//----------------------------------------------------------------
int ofSerialWrite (string str){


	if (!bInited){
		printf("error: serial not inited\n");
		return 0;
	}


	//---------------------------------------------
	#ifdef TARGET_OSX
	//---------------------------------------------
	    int len = str.length();
	    int numWritten = write(fd, str.c_str(), len);
		printf("numWritten %i \n", numWritten);
	    return numWritten;
	//---------------------------------------------
    #endif
    //---------------------------------------------

    //---------------------------------------------
	#ifdef TARGET_WIN32
	//---------------------------------------------

	DWORD written;
	int len = str.length();
	if(!WriteFile(hComm, str.c_str(), len, &written,0)){
   		 printf("Can't write to com port");
   		 return 0;
  	}
  	return (int)written;
	//---------------------------------------------
	#endif
	//---------------------------------------------

}


/*

//----------------------------------------------------------------
int ofSerialRead(string *& buffer, int length){

	if (!bInited){
		printf("error: serial not inited\n");
		return 0;
	}

	char tmpBuff[1024];
	memset(tmpBuff, 0, 1024);

	//---------------------------------------------
	#ifdef TARGET_OSX
	//---------------------------------------------
    int nRead = read(fd, tmpBuff,length);	
	if( strlen(tmpBuff) != 0)buffer = tmpBuff;;	
    return nRead;
	//---------------------------------------------
    #endif
    //---------------------------------------------

    //---------------------------------------------
	#ifdef TARGET_WIN32
	//---------------------------------------------
	DWORD nRead;
	if (!ReadFile(hComm,tmpBuff,length,&nRead,0)){
      printf("trouble reading from port\n");
      return 0;
    } 
        
	if( strlen(tmpBuff) != 0)buffer = tmpBuff;;	
	return (int)nRead;
	//---------------------------------------------
	#endif
	//---------------------------------------------

}

*/


