/**************************************************************************
<MODULE NAME>
<FILENAME>Serial.cpp</FILENAME>
<HISTORY>
	<MODIFICATION>
		<DATE>05/01/2006</DATE>
		<AUTHOR>DRO</AUTHOR>
		<DESCRIPTION>
			First version.
		</DESCRIPTION>
	</MODIFICATION>
</HISTORY>
</MODULE NAME>
**************************************************************************/ 
/*
    If the service requested is either initialize or status, additional 
	status information are returned in the low byte:
*/

/**************************************************************************
INCLUDE FILE
**************************************************************************/
#include <stdio.h>
#include <dos.h>
#include <mem.h>
#include <conio.h>
#include "..\comp\ComPort\Serial.h"

#define ETX			0x03

/**************************************************************************
LOCAL VARIABLES
Always start with « static »-keyword
**************************************************************************/

/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME>CSerial</NAME>
	<TYPE>GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
</METHOD>
**************************************************************************/
CSerial::CSerial()
{
	m_iOpened = 0;
	m_iPort   = 0;
}

/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME>~CSerial</NAME>
	<TYPE>GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
</METHOD>
**************************************************************************/
CSerial::~CSerial()
{
	Close();
}

#pragma argsused
/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME>Open</NAME>
	<TYPE>GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
	<PARAMETERS>
		<PARAMETER>
			<NAME></NAME>
			<TYPE></TYPE>
			<IO>IN</IO>
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
		<PARAMETER>
			<NAME></NAME>
			<TYPE></TYPE>
			<IO>IN</IO>
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
	</PARAMETERS>
	<RETURNS>
		<TYPE></TYPE>
		<DESCRIPTION>
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
int CSerial::Open(int iPort, int iSetting)
{
	int iResult = ERROR_OPEN_SERIAL;
	if( m_iOpened ) 
	{/* Opened*/
		iResult = ACK;
	}
	else
	{
		unsigned int uiStatus = ACK;
		uiStatus = _bios_serialcom(eComInit , iPort, iSetting);
		
		/*
		if ( uiStatus & eDsr)
		{
			if ( uiStatus & eCts)
			{
			*/
				m_iOpened = 1;
				iResult = ACK;
				m_iPort = iPort;
				/*
			}
			else
			{
				iResult = eNoCts;
			}
		}
		else
		{
			iResult = eNoDsr;
		}
		*/
	}
	return iResult;
}

/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME></NAME>
	<TYPE >LOCAL | GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
	<PARAMETERS>
		<PARAMETER>
			<NAME></NAME>
			<TYPE></TYPE>
			<IO> IN | OUT | INOUT</ IO >
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
	</PARAMETERS>
	<RETURNS>
		<TYPE></TYPE>
		<DESCRIPTION>
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
int CSerial::Close(void)
{
	int iResult = ERROR_CLOSE_SERIAL;
	if(!m_iOpened) 
	{ /* Closed */
		iResult = ACK;
	}
	else
	{
		/*unsigned int uiStatus = 0;

		uiStatus = _bios_serialcom(eC , m_iPort, iSetting);
		if (uiStatus)
		{*/
			m_iOpened = 0;
			iResult = ACK;
		/*}*/
	}
	return iResult;
}

/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME></NAME>
	<TYPE >LOCAL | GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
	<PARAMETERS>
		<PARAMETER>
			<NAME>ucByte</NAME>
			<TYPE>unsigned char</TYPE>
			<IO>IN</IO>
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
	</PARAMETERS>
	<RETURNS>
		<TYPE></TYPE>
		<DESCRIPTION>
			If the send service is requested but data cannot be sent, 
			bit 15 is set.
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
int CSerial::WriteByte( unsigned char ucByte )
{
	int iResult = ACK;	

	if( m_iOpened ) 
	{
		unsigned int uiStatus = ACK;

		uiStatus = _bios_serialcom(eComSend, m_iPort, ucByte);
		
		if(uiStatus & (eTimeOutError | eBreakError)) /*PMD*/
		{
#ifdef STESUD_TRACE
			printf("\r\n  ********* WriteByte Error %c", ucByte );
#endif
				iResult = ERROR_TIMEOUT_SERIAL;
		}
	}
	return iResult;
}

/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME></NAME>
	<TYPE >LOCAL | GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
	<PARAMETERS>
		<PARAMETER>
			<NAME></NAME>
			<TYPE></TYPE>
			<IO> IN | OUT | INOUT</ IO >
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
	</PARAMETERS>
	<RETURNS>
		<TYPE></TYPE>
		<DESCRIPTION>
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
int CSerial::SendData( const char *buffer, int size )
{
	int iResult = ERROR_SEND_DATA_SERIAL;
	int icpt = 0;
	const int ctiErrorMax = 5;

	if( m_iOpened )
	{
		int i;
		for( i = 0; (i < size) && (icpt < ctiErrorMax); i++ )
		{
			icpt = 0;
			do
			{
				iResult = WriteByte( buffer[i] );
				if(iResult < 0)
				{
#ifdef STESUD_TRACE
					printf("\r\n *** Error SendData %s", buffer);
#endif
					icpt++;
					/*delay(10);*/
				} // end if(iResult < 0)
			} // end do
			while(icpt < ctiErrorMax && iResult < 0 );
		} // end for( i = 0; i < size; i++ )
		
	} // end if( m_iOpened )
	
	return iResult;
}
/***************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME></NAME>
	<TYPE >LOCAL | GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
	<PARAMETERS>
		<PARAMETER>
			<NAME></NAME>
			<TYPE></TYPE>
			<IO> IN | OUT | INOUT</ IO >
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
	</PARAMETERS>
	<RETURNS>
		<TYPE></TYPE>
		<DESCRIPTION>
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
int CSerial::ReadDataWaiting( void )
{
	int iResult = -1;
	if( m_iOpened ) 
	{
		iResult = 0;
	}
	return iResult;
}

/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME>ReadData</NAME>
	<TYPE>GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
	<PARAMETERS>
		<PARAMETER>
			<NAME>buffer</NAME>
			<TYPE>vod*</TYPE>
			<IO>OUT</ IO >
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
		<PARAMETER>
			<NAME>limit</NAME>
			<TYPE>int</TYPE>
			<IO>IN</IO>
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
	</PARAMETERS>
	<RETURNS>
		<TYPE>unsigned long</TYPE>
		<DESCRIPTION>		
			The number of byte readed is returned in the low word. 
			If an error occurrs, at least one bit in the high word 
			is set to indicate the source of the error.
				Bit 	Meaning when set
				15 		Timed out
				14 		Transmitter Shift register empty
				13 		Transmitter Holding register empty
				12 		Break detected
				11 		Framing Error
				10 		Parity Error
				9 		Overrun Error
				8 		Data Ready
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
unsigned long CSerial::ReadDataWaitingETX( char *buffer, int limit )
{
	unsigned long ulResult = 0;
	if(m_iOpened) 
	{		
		unsigned long  ulClock, ulComputeClock; /*Timeout variable*/
		unsigned int uiCpt = 0;				/*counter of char*/
		unsigned int uiStatus = 0;			/*Status storage*/

		ulClock = biostime(0,0l);
		do
		{
			uiStatus = GetStatus();
			/*Get tick pc. Warning at midnight the value is given 0*/
			if((ulComputeClock = biostime(0,0l)) < ulClock)
				ulComputeClock += UTT_TICK_IN_A_DAY;
			ulComputeClock -= ulClock;
		} 
		while (((uiStatus & eDataReady) == 0) &&(ulComputeClock < TIME_OUT_SERIAL));
/* << 9.06 */
/*		if((uiStatus & eDataReady) == 0)*/
		if (ulComputeClock >= TIME_OUT_SERIAL)
		{
			ulResult = MY_TIME_OUT_ERROR_SERIAL;
		}
		else if((uiStatus & eDataReady) == 0)
/* 9.06 >> */
		{ /* Timeout*/
			ulResult = ((uiStatus & 0xff00) << 8);
		}
		else
		{
			do
			{
				/* Read one char*/
				uiStatus = _bios_serialcom( eComReceive, m_iPort, 0);

/* << 9.06 */
				/*If char read equal 0 then buffer empty */
/*				if((uiStatus & 0xff) != 0)
				{
					/ Test if timeout /
					if((uiStatus & eTimeOutError) != 0)
					{
						if(uiStatus & (eTsrEmpty | eThrEmpty) == 0)
*/
				if((uiStatus & (eTimeOutError | eBreakError |	eOverrunError | eParityError)) != 0)
				{
/* 9.06 >> */
						{
							ulResult |= ((uiStatus & 0xff00) << 8);
#ifdef STESUD_TRACE
							printf("\r\n  CSerial::ReadData Error 0x%X", uiStatus);
#endif
						}
						break;
					}
/* << 9.06 */
				/*If char read equal 0 then buffer empty */
				if((uiStatus & 0xff) != 0)
				{
					/* Test if timeout*/
					{
/* 9.06 >> */
						buffer[uiCpt++] = (uiStatus & 0x00FF);
						ulResult = (ulResult & 0xFFFF0000) | uiCpt;
						if(uiCpt > 1)
							if(buffer[uiCpt - 2] == ETX)
								break;
					} // end else if((uiStatus & eTimeOutError) != 0)
				} // end if(uiStatus & 0xff) != 0)
			} // end do
			while ((0x00 != (uiStatus & 0xFF) ) && (uiCpt < limit));
		}
	}
	return ulResult;
}

/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME>ReadData</NAME>
	<TYPE>GLOBAL</TYPE>
	<DESCRIPTION></DESCRIPTION>
	<PARAMETERS>
		<PARAMETER>
			<NAME>buffer</NAME>
			<TYPE>vod*</TYPE>
			<IO>OUT</ IO >
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
		<PARAMETER>
			<NAME>limit</NAME>
			<TYPE>int</TYPE>
			<IO>IN</IO>
			<DESCRIPTION>
			</DESCRIPTION>
		</PARAMETER>
	</PARAMETERS>
	<RETURNS>
		<TYPE>unsigned long</TYPE>
		<DESCRIPTION>		
			The number of byte readed is returned in the low word. 
			If an error occurrs, at least one bit in the high word 
			is set to indicate the source of the error.
				Bit 	Meaning when set
				15 		Timed out
				14 		Transmitter Shift register empty
				13 		Transmitter Holding register empty
				12 		Break detected
				11 		Framing Error
				10 		Parity Error
				9 		Overrun Error
				8 		Data Ready
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
int CSerial::ReadByte(void)
{
	int iResult = 0xff00;
	if(m_iOpened) 
	{
		iResult = _bios_serialcom( eComReceive, m_iPort, 0);
	}
	return iResult;
}
/**************************************************************************
<METHOD>
	<CLASS>CSerial</CLASS>
	<NAME>GetStatus</NAME>
	<TYPE >GLOBAL</TYPE>
	<DESCRIPTION> Return the status of opened port</DESCRIPTION>
	<RETURNS>
		<TYPE>unsigned int </TYPE>
		<DESCRIPTION>
			A 16-bit integer whose high byte contains status bits. The low byte
			varies according to the service requested. High byte status bits are:
			Bit 	Meaning when set
			15 	Timed out
			14 	Transmitter Shift register empty
			13 	Transmitter Holding register empty
			12 	Break detected
			11 	Framing Error
			10 	Parity Error
			9 	Overrun Error
			8 	Data Ready
			7 	Data Carrier Detect (DCD) state
			6 	Ring Indicator (RI) state
			5 	Data Set Ready (DSR) state
			4 	Clear To Send (CTS) state
			3 	Change in DCD
			2 	Change in RI
			1 	Change in DSR
			0 	Change in CTS
		</DESCRIPTION>
	</RETURNS>
</METHOD>
**************************************************************************/
unsigned int CSerial::GetStatus(void)
{
	unsigned int uiResult = -1;
	if(m_iOpened) 
	{
		uiResult = _bios_serialcom( eComStatus, m_iPort, 0);
	}
	return uiResult;
}