
/******************************************************************************
 * FILE:			SerialDevice.cpp:	
 *
 * Description:	This file is the interface for which to to interface
 *		with serial port sensors. The usage of this is as
 *		follows:
 *		1) 	inherit the interface to a specfic sensor
 *		2) 	fill in the structure of SerialPort and
 *		   	pass it to initSerialPort().
 *		   	NOTE: SerialPort is defined in SerialPort.h
 *		3) 	implement the parse function, you can use
 *		   	the serialData pointer to hold your structure.
 *		   	*((*LogginStringIn)serialData) = loggingStringIn;
 *		4) 	implement the setSystem Data function.
 *		5)	register your serialDevice object by calling.
 *			ssObjPtr->registerSelf();
 *		Let SerialDeviceMG handle the the rest.
 *
 *		NOTE: SerialDeviceMG keeps a reference count on the number
 *			of SerialDevice objects around. SerialDeviceMG::run()
 *			- run() will continually call parse()/setSystemData()
 *			on all the Serial Device objects.					
 *
 * DATE of Creation:			Oct. 13 / 2002				       	
 * DATE of last Modification:			NOV. 8 / 2002
 *****************************************************************************/

#include "serial_device.h" 


/* initialization of the serial sensor object counter */
int SerialDevice::numSerialSensors = 0;
char SerialDevice::parityError = '\377';

/********************************************************************
 * constructor 
 *******************************************************************/
SerialDevice::SerialDevice(char* devName, int pd, int typ)
{
	strcpy(deviceName, devName);
	this->period = pd;
	this->type = typ;	
	++numSerialSensors;
	fdHandle = -1;
}


/********************************************************************
 * destructor 
 *******************************************************************/
SerialDevice::~SerialDevice()
{
	--numSerialSensors;
	close(fdHandle);
}


/********************************************************************
 * initializes the serial ports:
 *	we have facaded the Posix termios to an easier, OO interface.
 *				 
 *	arguments: 
 *		baudrate:	0 - 9600
 *				1 - 38400
 *				2 - 57600
 *				3 - 115200
 *				NOTE: we can extend this, but
 *				for our purposes, this is enough. 	
 *		chSize		0 - 7
 *				1 - 8
 *		parity:		0 - even
 *				1 - odd
 *				2 - none
 *		nStopBits:	1 - 1 stop bit
 *				2 - 2 stop bits
 *		loption		1 - default - canonical input,
 *				    line oriented, CRLF
 *				0 - raw input - unprocessed
 *
 ********************************************************************/			
bool
SerialDevice::initSerialPort(	int baudrate, int chSize,  
				int parity, int nStopBits, int loption)
{
        struct termios newtio;			// just temp
        bzero(&newtio, sizeof(newtio));

	/* try opening up the port */
	if ((fdHandle = open(deviceName, O_RDWR | O_NOCTTY | O_NDELAY)) < 0) {
	//if ((fdHandle = open(deviceName, O_RDWR | O_NOCTTY)) < 0) {	
		// could not open port
		cerr << "SerialDevice: couldn't open " << deviceName << endl;
		return false;
	}

	/***************** c_cflag - control options ******************/
	/* enable receiver and set local mode */
	newtio.c_cflag |=  (CREAD | CLOCAL);

        switch (baudrate) {
		case 0:
			// 9600
                	newtio.c_cflag |=  B9600;
			break;
                case 1:
			// 38400
			newtio.c_cflag |=  B38400;
			break;
		case 2:
			// 57600
			newtio.c_cflag |=  B57600;
			break;
		case 3: 
			// 115200        
			newtio.c_cflag |=  B115200;
			break;
		default:
			// 9600
                	newtio.c_cflag |=  B9600;
			break;
	}

	
	newtio.c_cflag &= ~CSIZE;

	switch (chSize) {
		case 0:
			// 7 character size
			newtio.c_cflag |= CS7;
			break;
		case 1:
			// 8 character size
			newtio.c_cflag |= CS8;
			break;
		default:
			// 8 character size
			newtio.c_cflag |= CS8;
			break;
	}

	switch (parity) {
		case 0:
			// even
			newtio.c_cflag |= PARENB;
			newtio.c_cflag &= ~PARODD;
			break;
		case 1:
			// odd
			newtio.c_cflag |= PARENB;
			newtio.c_cflag |= PARODD;
			break;
		case 2:
			// none
			newtio.c_cflag &= ~PARENB;
		default:
			// none
			newtio.c_cflag &= ~PARENB;
	}	

	switch (nStopBits) {
		case 1:
			// 1 stop bit
                	newtio.c_cflag &= ~CSTOPB;
			break;
		case 2:
			// 2 stop bits
		 	newtio.c_cflag |= CSTOPB;
			break;
		default:
			// 1 stop bit
			break;
	}


	/***************** c_lflag - line options ******************/
       
	if (loption == 1)
		newtio.c_lflag |= ICANON;	// canonical input mode
	else
		newtio.c_lflag &= ~ICANON;	// raw input mode

        //Daves test of quit signal from teleos
        newtio.c_lflag |= ISIG;

		
	/**************** c_iflag - input options ******************/	
	//if (parity == 2) {
		// ignore parity
		//newtio.c_iflag |= (IGNPAR|ISTRIP|ICRNL);
	//} else {
		/* enable parity, strip parity bit,
		 * map CR to NL,
		 * NOTE: future extension - PARMRK to
		 * 	 count bad parity characters
		 */
		newtio.c_iflag |= (INPCK | PARMRK | ISTRIP| ICRNL);
	//}

	/*************** c_cc - control character ******************/
        /* initialize all control characters, default in termio.h */
        newtio.c_cc[VINTR]      = 0;
        newtio.c_cc[VQUIT]      = 0;
        newtio.c_cc[VERASE]     = 0;
        newtio.c_cc[VKILL]      = 0;
        newtio.c_cc[VEOF]       = 4;
        newtio.c_cc[VTIME]      = 0;
        newtio.c_cc[VMIN]       = 100;
        newtio.c_cc[VSWTC]      = 0;
        newtio.c_cc[VSTART]     = 0;
        newtio.c_cc[VSTOP]      = 0;
        newtio.c_cc[VSUSP]      = 0;
        newtio.c_cc[VEOL]       = 0;
        newtio.c_cc[VREPRINT]   = 0;
        newtio.c_cc[VDISCARD]   = 0;
        newtio.c_cc[VWERASE]    = 0;
        newtio.c_cc[VLNEXT]     = 0;
        newtio.c_cc[VEOL2]      = 0;

	
	/**************** c_oflag - output options ******************/	
        /* we almost always want raw output
	 * if you need output processing, you will need
 	 * to override this function. Consult APUE - Stevens
 	 */
	newtio.c_oflag &= ~OPOST;


        /* clean the line and activate settings for port */
        tcflush(this->fdHandle, TCIOFLUSH);
        tcsetattr(this->fdHandle, TCSANOW, &newtio);

	return true;
}


const int
SerialDevice::handle()
{
	return fdHandle;
}

const int
SerialDevice::type_()
{
	return type;
}

const int
SerialDevice::frequency()
{
	return period;
}
const char*
SerialDevice::name()
{
	return deviceName;
}


