/*	PONTECH Copyright 1996
 *	Date: 11/09/1996
 *  SVLIBVC.CPP
 *		SV200 library for use with VC++ 1.52
 *
 */

#include "stdafx.h"    	// comment out if not using MFC

//#include <windows.h>	// uncomment if not used with MFC
//#include <stdlib.h>   //   "
//#include <string.h>   //   "
//#include <time.h>     //   "

#include "svlibvc.h"

//--------------- COMM Class ---------------

static COM_ERRORS OpenErrors[] = {
{ IE_BADID, "The device identifier is invalid or unsupported." },
{ IE_BAUDRATE, "The device's baud rate is unsupported." },
{ IE_BYTESIZE, "The specified byte size is invalid." },
{ IE_DEFAULT, "The default parameters are in error." },
{ IE_HARDWARE, "The hardware is not available (is locked by another device)." },
{ IE_MEMORY, "The function cannot allocate the queues." },
{ IE_NOPEN, "The device is not open." },
{ IE_OPEN, "The device is already open." }
};
	
static COM_ERRORS WriteErrors[] = {
{ CE_BREAK, "Hardware detected a break condition." },
{ CE_CTSTO, "CTS (clear-to-send) timeout. While a character was being transmitted, CTS was low for the duration specified by the fCtsHold member of the COMSTAT structure." },
{ CE_DNS, "Parallel device was not selected." },
{ CE_DSRTO, "DSR (data-set-ready) timeout. While a character was being transmitted, DSR was low for the duration specified by the fDsrHold member of COMSTAT." },
{ CE_FRAME, "Hardware detected a framing error." },
{ CE_IOE, "I/O error occurred during an attempt to communicate with a parallel device." },
{ CE_MODE, "Requested mode is not supported, or the idComDev parameter is invalid. If set, CE_MODE is the only valid error." },
{ CE_OOP, "Parallel device signaled that it is out of paper." },
{ CE_OVERRUN, "Character was not read from the hardware before the next character arrived. The character was lost." },
{ CE_PTO, "Timeout occurred during an attempt to communicate with a parallel device." },
{ CE_RLSDTO, "RLSD (receive-line-signal-detect) timeout. While a character was being transmitted, RLSD was low for the duration specified by the fRlsdHold member of COMSTAT." },
{ CE_RXOVER, "Receiving queue overflowed. There was either no room in the input queue or a character was received after the end-of-file character was received." },
{ CE_RXPARITY, "Hardware detected a parity error." },
{ CE_TXFULL, "Transmission queue was full when a function attempted to queue a character." }
};

CComm::CComm( int Port, long Baud, int Parameters, UINT Transmit, UINT Receive )
{
	static char *Params[] = { "n,8,1", "e,7,1" };
	int err;
	DCB dcb;
		
	// Initialize the class variables and set the
	// Message queue structures to zero.
	mError[0] = 0;
	mErrorNumber = 0;
	mOpened = FALSE;
	mHeadIn = mTailIn = mHeadOut = mTailOut = 0;
	mBufferPointer = 0;
	
	// Allocate the memory buffer.
	mBuffer = new unsigned char [BUFFER_SIZE];
	if( !mBuffer )
	{
		mErrorNumber = 0x1010;
		lstrcpy( mError, "Memory allocation failed!" );
		goto BailOut;
	}

	// Assign the passed in values for the size of
	// the transmit and receive buffers to mTransmit
	// and mReceive. Make sure they're in range, too.
	mTransmit = Transmit;
	if( mTransmit < 500 ) mTransmit = 500;
	else if( mTransmit > 60000 ) mTransmit = 60000;
	mReceive = Receive;
	if( mReceive < 500 ) mReceive = 500;
	else if( mReceive > 60000 ) mReceive = 60000;
	
	// Assign the passed value for the communications
	// parameters to mParameters. Make sure we have a value
	// that's in range.
	mParameters = Parameters;
	if( mParameters != _7E1 && mParameters != _8N1 ) mParameters = _8N1;		
	
	// Assign the passed value for the baud rate
	// to mBaud. Make sure it's in range.
	mBaud = Baud;
	if( mBaud == 14400 ) mBaud = 19200;
	if( mBaud != 300 &&
		mBaud != 1200 &&
		mBaud != 2400 &&
		mBaud != 9600 &&
		mBaud != 19200 &&
		mBaud != 38400 ) mBaud = 9600;

	// Assign the passed value for the port number
	// to mPort. Make sure it's in range.
	mPort = Port;
	if( mPort < 1 || mPort > 9 ) mPort = 1;

	// Build the COM port string.
	char junk[100];
	wsprintf( junk, "COM%d", mPort );

	// Attempt to open the com port. Error trap if
	// something goes wrong.
	mIDComDev = OpenComm( junk, Receive, Transmit );
	if( mIDComDev < 0 )
	{
		AssignOpenError( mIDComDev );
		goto BailOut;
	}

	// Build the string we'll use to construct the DCB.
	wsprintf( junk, "COM%d:%ld,%s",
	mPort, mBaud, (LPSTR) Params[mParameters-1] );

	// Build the DCB. Error trap if something goes wrong.
	err = BuildCommDCB( junk, &dcb );
	if( err < 0 )
	{
		CloseComm( mIDComDev );
		AssignOpenError( err );
		goto BailOut;
	}
		
	// Set the communication channel state. Error trap if
	// something goes wrong.
	err = SetCommState( &dcb );
	if( err < 0 )
	{
		CloseComm( mIDComDev );
		AssignOpenError( err );
		goto BailOut;
	}

	// Set our flag to indicate success.
	mOpened = TRUE;

;
BailOut:
;

}

CComm::~CComm()
{
	// If we've set mOpened to true and have a
	// valid communcation port id, close the com port.
	if( mOpened && mIDComDev >= 0 )
		CloseComm( mIDComDev );

	// If we successfully allocate the buffer, delete the memory.
	if( mBuffer ) delete [] mBuffer;
}

void CComm::AssignOpenError( int Error )
{
	int i;

	// We'll store the error
	// number in mErrorNumber and try to find
	// a match in our error list so we can
	// store an error text string in mError.
	// Search through the error numbers and
	mErrorNumber = Error;
	for( i=0; i<NUM_OPENERRORS; i++ )
	{
		if( Error == OpenErrors[i].ErrorNumber )
		{
			lstrcpy( mError, OpenErrors[i].ErrorText );
			return;
		}
	}
	lstrcpy( mError, "Unknown error number." );

}

void CComm::AssignReadWriteError( int Error )
{
	int i;

	// We'll store the error
	// number in mErrorNumber and try to find
	// a match in our error list so we can
	// store an error text string in mError.
	// Search through the error numbers and
	mErrorNumber = Error;
	for( i=0; i<NUM_WRITEERRORS; i++ )
	{
		if( Error == WriteErrors[i].ErrorNumber )
		{
			lstrcpy( mError, WriteErrors[i].ErrorText );
			return;
		}
	}
	lstrcpy( mError, "Unknown error number." );
}

void CComm::FlushIncoming( void )
{
	DWORD Ticks;
	char junk[2048];
	
	if( mIDComDev < 0 ) return;

	FlushComm( mIDComDev, 1 );
	do
	{
		Ticks = ::GetTickCount();
		while( Ticks == ::GetTickCount())
			;
	} while( GetBlock( junk, GetLength() ) );

}

int CComm::SendStr( void *data )
{
	int err;
	
	if( mIDComDev < 0 ) return( 0 );

	mErrorNumber = 0;
	
	int size = strlen((char*)data);
	err = WriteComm( mIDComDev, data, size );
	if( err < 0 )
	{
		AssignReadWriteError( GetCommError( mIDComDev, NULL ) );
		return( -err );
	}

	return( err );
}

int CComm::SendBlock( void *data, int size )
{
	int err;
	
	if( mIDComDev < 0 ) return( 0 );

	mErrorNumber = 0;

	err = WriteComm( mIDComDev, data, size );
	if( err < 0 )
	{
		AssignReadWriteError( GetCommError( mIDComDev, NULL ) );
		return( -err );
	}
	return( err );
}

int CComm::GetBlock( void *data, int len )
{
	int err;
	
	if( mIDComDev < 0 ) return( 0 );

	mErrorNumber = 0;

	// Read a block, and store errors if there are any.
	err = ReadComm( mIDComDev, data, len );
	if( err < 0 )
	{
		AssignReadWriteError( GetCommError( mIDComDev, NULL ) );
		return( -err );
	}

	return( err );
}

char CComm::GetCh( void )
{                                     
	char data;
	
	ReadComm( mIDComDev, &data, 1 );

	return( data );
}

int CComm::GetLength( void )
{
	COMSTAT stat;
	
	if( mIDComDev < 0 ) return( 0 );

	GetCommError(mIDComDev, &stat);   
	
	return (stat.cbInQue); // return Length of Recieve Buffer
}

//--------------- SV200 Class ---------------

SV200::SV200(int comPort, int baudRate)
{
	comm = new CComm(comPort, baudRate);	// open comm port
	comm->FlushIncoming();

	svSelect = 1;
	for (int i = 0; i < 8; i++)
	{
		savePosition[i] = 0;
	}
}

SV200::~SV200()
{
	delete comm;
}

void SV200::serlXmitStr(char *str)
{
	comm->SendStr(str);
}

void SV200::svCmmd(char *cmmd, int param)
{
	serlXmitStr(cmmd);
	itoa(param, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr("\r");
}

void SV200::svCmmd2(char *cmmd, int param1, int param2)
{
	serlXmitStr(cmmd);
	itoa(param1, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr(" ");
	itoa(param2, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr("\r");
}

void SV200::selectBoard(int board)
{
	serlXmitStr("BD");
	itoa(board, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr("\r");
}

void SV200::selectServo(int servo)
{
	serlXmitStr("SV");
	itoa(servo, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr("\r");
	svSelect = servo;
}

void SV200::moveSelect(int position)
{
	serlXmitStr("M");
	itoa(position, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr("\r");
	savePosition[svSelect] = position;
}

void SV200::move(int servo, int position)
{
	serlXmitStr("SV");
	itoa(servo, numStr, 10);
	serlXmitStr(numStr);

	serlXmitStr("M");
	itoa(position, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr("\r");
	savePosition[servo-1] = servo;
}

void SV200::moveAll(int S1, int S2, int S3, int S4, int S5, int S6, int S7, int S8)
{
	if ((S1 >= 0) && (S1 <= 255))
	{
		serlXmitStr("SV1M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[0] = S1;
	}
	if ((S2 >= 0) && (S2 <= 255))
	{
		serlXmitStr("SV2M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[1] = S2;
	}
	if ((S3 >= 0) && (S3 <= 255))
	{
		serlXmitStr("SV3M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[2] = S3;
	}
	if ((S4 >= 0) && (S4 <= 255))
	{
		serlXmitStr("SV4M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[3] = S4;
	}
	if ((S5 >= 0) && (S5 <= 255))
	{
		serlXmitStr("SV5M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[4] = S5;
	}
	if ((S6 >= 0) && (S6 <= 255))
	{
		serlXmitStr("SV6M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[5] = S6;
	}
	if ((S7 >= 0) && (S7 <= 255))
	{
		serlXmitStr("SV7M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[6] = S7;
	}
	if ((S8 >= 0) && (S8 <= 255))
	{
		serlXmitStr("SV8M");
		itoa(S1, numStr, 10);
		serlXmitStr(numStr);
		savePosition[7] = S8;
	}
	serlXmitStr("\r");
}

int SV200::getNum(void)
{
	int i;
	unsigned char ch;
	time_t tm;
	char result[10];

	// Read the ascii string into result
	i = 0;
	do
	{
		tm = time(NULL);
		while (comm->GetLength() <= 0)
		{
			if ((time(NULL) - tm) >= 2)
			{
				result[0] = 0;
				return -1;
			}
		}
		ch = comm->GetCh();

		if (ch == 13)
			ch = 0;
		if (ch != 10)
			result[i++] = ch;

	} while (ch != 0);
	result[i] = '\0';

	return atoi(result);
}


unsigned char SV200::getAD(int channel)
{
	serlXmitStr("AD");
	itoa(channel, numStr, 10);
	serlXmitStr(numStr);
	serlXmitStr("\r");

	return (unsigned char) getNum();
}

int SV200::adjADJoystick(int position)
{
	return (((position-128) * 2) + 128);
}
