connectivity/com.nokia.tcf/native/TCFNative/TCFCommSerial/RealSerialComm.cpp
author timkelly
Tue, 31 Aug 2010 17:03:48 -0500
changeset 1931 d7c1f804f316
parent 1481 c7f22cc57d44
permissions -rw-r--r--
using IRunnableContext for retrieving BuildTargetTreeNode input so progress dialog can be displayed for wizards or in the status bar when on the UI thread (e.g. ManageConfigurationsDialog) Removes API in BuildTargetTreeNode that presumed all nodes were SBSv1 (didn't appear to be used anywhere)

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/
// RealSerialComm.cpp: implementation of the CRealSerialComm class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "RealSerialComm.h"
//#include "pn_const.h"
//#include "OSTConstants.h"
#include "Connection.h"

#ifdef _DEBUG
//static char sLogMsg[3000];
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#define LogErrorText(err) { if (err > 0) GetErrorText(err); }
#define LogErrorText2(err) { if (err > 0) GetErrorText2(err); }
#else
#define LogErrorText(err) {}
#define LogErrorText2(err) {}
#endif

#ifdef _DEBUG
#define DUMPCOMSTAT(x) DumpComStat(x)
#define DUMPCOMSTATP(x) DumpComStatP(x)
#else
#define DUMPCOMSTAT(x)
#define DUMPCOMSTATP(x)
#endif

CRealSerialComm::CRealSerialComm()
{
#ifdef _DEBUG
	if (gDoLogging)
	{
		FILE* f = fopen("c:\\tcf\\rscommlog.txt", "at");
		fprintf(f, "CRealSerialComm::CRealSerialComm() (default constructor)\n");
		fclose(f);
	}
#endif
	m_hSerial = INVALID_HANDLE_VALUE;
	m_serialPortName[0] = 0;
	m_pBuffer = NULL;
	m_ProcDebugLog = NULL;

}
CRealSerialComm::CRealSerialComm(ConnectData* connectSettings, DWORD connectionId, CBaseProtocol* protocol)
{
#ifdef _DEBUG
	if (gDoLogging)
	{
		FILE* f = fopen("c:\\tcf\\rscommlog.txt", "at");
		fprintf(f, "connectSettings=%x connectionId=%d, protocol=%x\n", connectSettings, connectionId, protocol);
		fclose(f);
	}
#endif
	m_hSerial = INVALID_HANDLE_VALUE;
	m_serialPortName[0] = 0;
	m_pBuffer = NULL;

	m_connId = connectionId;
	m_Protocol = protocol;

	m_ConnectSettings = new ConnectData();
	memcpy(m_ConnectSettings, connectSettings, sizeof(ConnectData));

#if (defined(LOG_COMM) || defined(LOG_PROCCOMM)) && defined(_DEBUG)
	if (gDoLogging)
	{
		m_CommDebugLog = new TCDebugLog("TCF_Comm", connectionId, 2000L);
		m_ProcDebugLog = new TCDebugLog("TCF_CommP", connectionId, 2000L);
	}
#endif
}
CRealSerialComm::~CRealSerialComm()
{
#ifdef _DEBUG
	if (gDoLogging)
	{
		FILE* f = fopen("c:\\tcf\\rscommlog.txt", "at");
		fprintf(f, "CRealSerialComm::~CRealSerialComm()\n");
		fclose(f);
	}
#endif
	if (m_hSerial != INVALID_HANDLE_VALUE)
		::CloseHandle(m_hSerial);

	if (m_pBuffer)
		delete[] m_pBuffer;

}

long CRealSerialComm::OpenPort()
{
	COMMLOGOPEN();
	COMMLOGS("CRealSerialComm::OpenPort\n");

	long err = TCAPI_ERR_NONE;

	char* comPort = m_ConnectSettings->realSerialSettings.comPort;
	DWORD baudRate = m_ConnectSettings->realSerialSettings.baudRate;
	DWORD dataBits = m_ConnectSettings->realSerialSettings.dataBits;
	eParity parity = m_ConnectSettings->realSerialSettings.parity;
	eStopBits stopBits = m_ConnectSettings->realSerialSettings.stopBits;
	eFlowControl flow = m_ConnectSettings->realSerialSettings.flowControl;

	COMMLOGA2("CRealSerialComm::OpenPort comPort=%s baudRate=%d\n", comPort, baudRate);
	COMMLOGA2("CRealSerialComm::OpenPort dataBits=%d parity=%d\n", dataBits, parity);
	COMMLOGA2("CRealSerialComm::OpenPort stopBits=%d flow=%d\n", stopBits, flow);

	// fill in DCB
	m_dcb.DCBlength = sizeof(DCB);
	m_dcb.BaudRate = baudRate;
	m_dcb.ByteSize = dataBits;

	// parity
	switch(parity)
	{
	default:
	case eParityNone:
		m_dcb.fParity = FALSE;
		m_dcb.Parity = NOPARITY;
		break;
	case eParityEven:
		m_dcb.fParity = TRUE;
		m_dcb.Parity = EVENPARITY;
		break;
	case eParityOdd:
		m_dcb.fParity = TRUE;
		m_dcb.Parity = ODDPARITY;
		break;
	}

	// stop bits
	switch(stopBits)
	{
	default:
	case eStopBits1:
		m_dcb.StopBits = ONESTOPBIT;
		break;
	case eStopBits15:
		m_dcb.StopBits = ONE5STOPBITS;
		break;
	case eStopBits2:
		m_dcb.StopBits = TWOSTOPBITS;
		break;
	}

	// flow control
	switch(flow)
	{
	default:
	case eFlowControlNone:
		m_dcb.fRtsControl = RTS_CONTROL_DISABLE;
		m_dcb.fOutxCtsFlow = FALSE;
		m_dcb.fInX = m_dcb.fOutX = FALSE;
		break;
	case eFlowControlHW:
		m_dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
		m_dcb.fOutxCtsFlow = TRUE;
		m_dcb.fInX = m_dcb.fOutX = FALSE;
		break;
	case eFlowControlSW:
		m_dcb.fRtsControl = RTS_CONTROL_DISABLE;
		m_dcb.fOutxCtsFlow = FALSE;
		m_dcb.fInX = m_dcb.fOutX = TRUE;
		m_dcb.XonChar = '\021';	// Ctrl-Q;
		m_dcb.XoffChar = '\023';	// Ctrl-S;
		m_dcb.XonLim = 100;
		m_dcb.XoffLim = 100;
		break;
	}

	// other things in DCB
	m_dcb.fDtrControl = DTR_CONTROL_ENABLE;	
	m_dcb.fDsrSensitivity = FALSE;
	m_dcb.fBinary = TRUE;
	m_dcb.fNull = FALSE;
	m_dcb.fAbortOnError = TRUE;		// reads & writes will terminate with errors if one occurs

	// translate serial port
	char p[20]; char* pp = p;
	strncpy(p, comPort, 20);
	int len = (int)strlen(p);
	for (int i = 0; i < len; i++)
	{
		p[i] = toupper(p[i]);
	}
	if (strncmp(p, "COM", 3) == 0)
	{
		pp+=3;
	}
	int val = atoi((const char*)pp);
	if (val == INT_MIN || val == INT_MAX)
	{
		err = TCAPI_ERR_INVALID_MEDIA_DATA;
	}
	else
	{
		// must translate for CreatFile
		_snprintf(m_serialPortName, MAX_COMPORT_SIZE, "\\\\.\\COM%d", val);
	}


	if (err == TCAPI_ERR_NONE)
	{
		m_hSerial = CreateFile(m_serialPortName,
			GENERIC_READ|GENERIC_WRITE,	// dwDesiredAccess = read & write
			0,							// dwSharedMode = 0 ==> device not shared
			NULL,						// lpSecurityAttributes = NULL ==> not inheritable
			OPEN_EXISTING,				// dwCreationDisposition ==> required for devices
			0,							// dwFlagsAndAttributes ==> no special flags or attributes (not overlapped)
			NULL );						// hTemplateFile = NULL ==> required for devices

		if (m_hSerial != INVALID_HANDLE_VALUE)
		{
			// TODO: this is really not needed as we're not doing overlapped IO
			//   and we're not creating an event nor waiting on that event
			if (!SetCommMask(m_hSerial, EV_RXCHAR))
			{
				::CloseHandle(m_hSerial);
				m_hSerial = INVALID_HANDLE_VALUE;
				m_lastCommError = GetLastError();
				err = TCAPI_ERR_WHILE_CONFIGURING_MEDIA;
			}
			else
			{
				// no error from SetCommMask
				if (!SetupComm(m_hSerial,MAX_MESSAGE_LENGTH,MAX_SERIAL_MESSAGE_BUFFER_LENGTH))
				{
					CloseHandle(m_hSerial);
					m_hSerial = INVALID_HANDLE_VALUE;
					m_lastCommError = GetLastError();
					err = TCAPI_ERR_WHILE_CONFIGURING_MEDIA;
				}
				else
				{
					// no error from SetupComm
					// Get rid of any junk that might be sitting there.
					PurgeComm( m_hSerial, PURGE_TXABORT | PURGE_RXABORT |
										  PURGE_TXCLEAR | PURGE_RXCLEAR );

					// Using these settings, the ReadFile command will return immediately
					// rather than waiting for a timeout.
					COMMTIMEOUTS lclCommTimeOuts;

					lclCommTimeOuts.ReadIntervalTimeout			= MAXDWORD;	// we don't care about time between chars
					lclCommTimeOuts.ReadTotalTimeoutMultiplier	= 100;
					lclCommTimeOuts.ReadTotalTimeoutConstant	= 0;
					lclCommTimeOuts.WriteTotalTimeoutMultiplier	= 100;
					lclCommTimeOuts.WriteTotalTimeoutConstant	= 0;
					
					if (!SetCommTimeouts( m_hSerial, &lclCommTimeOuts ))
					{
						CloseHandle(m_hSerial); 
						m_hSerial = INVALID_HANDLE_VALUE;
						m_lastCommError = GetLastError();
						err = TCAPI_ERR_WHILE_CONFIGURING_MEDIA;
					}
					else
					{
						// no error from SetCommTimeouts
						err = SetDCB();
						if (err != TCAPI_ERR_NONE)
						{
							CloseHandle(m_hSerial); 
							m_hSerial = INVALID_HANDLE_VALUE;
						}
						else
						{
							// no error from SetDCB 
							err = TCAPI_ERR_NONE;
							m_numberBytes = 0;
							m_lastCommError = 0;
							m_isConnected = true;
							m_pBuffer = new BYTE[MAX_SERIAL_MESSAGE_BUFFER_LENGTH];
						}
					}
				}
			}
		}
		else
		{
			// error from CreateFile
			// couldn't open serial port
			m_lastCommError = GetLastError();
			err = TCAPI_ERR_WHILE_CONFIGURING_MEDIA;
		}
	}

	COMMLOGA2("CRealSerialComm::OpenPort err=%d osError=%d\n", err, m_lastCommError);
	LogErrorText(m_lastCommError);
//	if (m_lastCommError > 0)
//		LogErrorText(m_lastCommError);
	COMMLOGCLOSE();
	return err;
}

long CRealSerialComm::SetDCB()
{
	// assumes serial port is open
	long err = TCAPI_ERR_NONE;
	if (m_hSerial == INVALID_HANDLE_VALUE)
		return err;

	// setup DCB
	DCB lcldcb;
	lcldcb.DCBlength = sizeof(DCB);

	if (!GetCommState( m_hSerial, &lcldcb ))
	{
		m_lastCommError = GetLastError();
		err = TCAPI_ERR_WHILE_CONFIGURING_MEDIA;
	}

//	LogDCB(pInfo);
	// copy only the ones that Connect() set initially
	lcldcb.BaudRate = m_dcb.BaudRate;
	lcldcb.ByteSize = m_dcb.ByteSize;
	lcldcb.Parity = m_dcb.Parity;
	lcldcb.StopBits = m_dcb.StopBits;
	lcldcb.fRtsControl = m_dcb.fRtsControl;
	lcldcb.fOutxCtsFlow = m_dcb.fOutxCtsFlow;
	lcldcb.fDtrControl = m_dcb.fDtrControl;
	lcldcb.fDsrSensitivity = m_dcb.fDsrSensitivity;
	lcldcb.fInX = m_dcb.fInX;
	lcldcb.fOutX = m_dcb.fOutX;
	lcldcb.XonChar = m_dcb.XonChar;
	lcldcb.XoffChar = m_dcb.XoffChar;
	lcldcb.XonLim = m_dcb.XonLim;
	lcldcb.XoffLim = m_dcb.XoffLim;
	lcldcb.fBinary = m_dcb.fBinary;
	lcldcb.fParity = m_dcb.fParity;
	lcldcb.fNull = m_dcb.fNull;
	lcldcb.fAbortOnError = m_dcb.fAbortOnError;

	// DCB has been changed
	// If setting the port went well then we are connected properly!
	if (!SetCommState( m_hSerial, &lcldcb))
	{
		m_lastCommError = GetLastError();
		err = TCAPI_ERR_WHILE_CONFIGURING_MEDIA;
	}

	return err;
}

long CRealSerialComm::ClosePort()
{
	COMMLOGOPEN();
	COMMLOGA1("CRealSerialComm::ClosePort connected=%d\n", IsConnected());

	long err = TCAPI_ERR_NONE;

	if (!IsConnected()) 
	{

		err = TCAPI_ERR_MEDIA_NOT_OPEN;
	}
	else if (m_hSerial != INVALID_HANDLE_VALUE)
	{
		// disable event notification 
		SetCommMask( m_hSerial, 0 );

		// drop DTR
		EscapeCommFunction( m_hSerial, CLRDTR );

		// purge any outstanding reads/writes and close device handle
		PurgeComm(	m_hSerial, 
					PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
		
		CloseHandle( m_hSerial );
		m_hSerial = INVALID_HANDLE_VALUE;

		if (m_pBuffer)
		{
			delete[] m_pBuffer;
			m_pBuffer = NULL;
		}
		m_isConnected = false;
	}

	COMMLOGCLOSE();
	return err;
}

void CRealSerialComm::DeleteMsg(DWORD inMsgLength)
{
	if (!IsConnected())
		return;
	// inMsgLength includes header
	// delete from beginning of buffer
	if (inMsgLength == 0)
		return;
	if (m_numberBytes > 0 && m_numberBytes >= inMsgLength)
	{
		size_t moveLen = m_numberBytes - inMsgLength;
		if (moveLen > 0)
			memcpy(&m_pBuffer[0], &m_pBuffer[inMsgLength], moveLen);
		m_numberBytes -= inMsgLength;
	}
}

long CRealSerialComm::SendDataToPort(DWORD inSize, const void *inData)
{

	long err = TCAPI_ERR_NONE;
	DWORD lclNumBytes=0;
	COMMLOGOPEN();
	COMMLOGS("CRealSerialComm::SendDataToPort\n");
	COMMLOGCLOSE();
	if (!IsConnected())
	{

		COMMLOGOPEN();
		COMMLOGS("CRealSerialComm::SendDataToPort notConnected\n");
		COMMLOGCLOSE();
		return TCAPI_ERR_MEDIA_NOT_OPEN;
	}

	if (WriteFile(m_hSerial, inData, inSize, &lclNumBytes, NULL))
	{
		// we were successful, but did we send all data? (i.e., a timeout occurred)
		// we are not doing overlapped I/O so if not all data went, then we timed out
		//   and there was some kind of error
		if (lclNumBytes != inSize)
		{
			m_lastCommError = 0;
			COMMLOGOPEN();
			COMMLOGA3("CRealSerialComm::SendDataToPort WriteFile not all bytes sent: lclNumBytes=%d inSize=%d err=%d\n", lclNumBytes, inSize, m_lastCommError);
			COMMLOGCLOSE();

			COMSTAT lclComStat;
			DWORD lclErrorFlags = 0;
			if (!ClearCommError(m_hSerial, &lclErrorFlags, &lclComStat))
			{
				// clear comm error returned error (this doesn't normally happen if the handle is valid and port is still open)
				m_lastCommError = GetLastError();
				err = TCAPI_ERR_COMM_ERROR;
				COMMLOGOPEN();
				COMMLOGA1("CRealSerialComm::SendDataToPort ClearCommError failed=%d\n", m_lastCommError);
				COMMLOGCLOSE();
			}
			else
			{
				// clear comm error returned OK
				// check error flags
				if (lclErrorFlags)
				{
					// there really was an error
					err = TCAPI_ERR_COMM_ERROR;
					COMMLOGOPEN();
					COMMLOGA1("CRealSerialComm::SendDataToPort ClearCommError succeeded lclErrorFlags=%d\n", lclErrorFlags);
					COMMLOGCLOSE();
				}
				else
				{
					// No OS error returned, but WriteFile failed to write out all bytes
					//  therefore, since we are not doing overlapped I/O, this is an error.
//					DUMPCOMSTAT(&lclComStat);
					BOOL flush = FlushFileBuffers(m_hSerial); // flush transmit buffer
//					ClearCommError(m_hSerial, &lclErrorFlags, &lclComStat);
//					if (WriteFile(m_hSerial, inData, inSize, &lclNumBytes, NULL))
//					{
//						COMMLOGOPEN();
//						COMMLOGA1("CRealSerialComm::SendDataToPort WriteFile#2 succeeded lclNumBytes=%d\n", lclNumBytes);
//						COMMLOGCLOSE();
//					}
					err = TCAPI_ERR_COMM_ERROR_DEVICE_NOT_READING;
					COMMLOGOPEN();
					COMMLOGA2("CRealSerialComm::SendDataToPort ClearCommError succeeded lclErrorFlags=0 err=%d flush=%d\n", m_lastCommError, flush);
					COMMLOGCLOSE();
//					DUMPCOMSTAT(&lclComStat);
				}
			}
		}
		else
		{
			// we sent all the data we requested
			err = TCAPI_ERR_NONE;
#ifdef _DEBUG
			COMMLOGOPEN();
			COMMLOGS("CRealSerialComm::SendDataToPort WriteFile successful\n");
			BYTE* ptr = (BYTE*)inData;
			long numBytes = (inSize > 80) ? 80 : inSize;
			char msg[300];
			sprintf(msg, "CRealSerialComm::SendDataToPort = ");
			for (int i = 0; i < numBytes; i++)
			{
				sprintf(msg, "%s %02.2x", msg, ptr[i]);
			}
			sprintf(msg, "%s\n", msg);
			COMMLOGS(msg);
			COMMLOGCLOSE();
#endif
		}
	}
	else
	{
		// write failed
		m_lastCommError = GetLastError();
		err = TCAPI_ERR_COMM_ERROR;
		COMMLOGOPEN();
		COMMLOGA1("CRealSerialComm::SendDataToPort WriteFile failed = %d\n", m_lastCommError);
		COMMLOGCLOSE();
	}
	
	return err;
}
long CRealSerialComm::PollPort(DWORD &outSize)
{
	long err = TCAPI_ERR_NONE;
	outSize = 0;

	COMSTAT lclComStat;
	DWORD lclErrorFlags=0;

	if (!IsConnected() || m_hSerial == INVALID_HANDLE_VALUE)
		return TCAPI_ERR_MEDIA_NOT_OPEN;


//	Sleep(1);
	if (!ClearCommError( m_hSerial, &lclErrorFlags, &lclComStat ))
	{
		if (!IsConnected() || m_hSerial == INVALID_HANDLE_VALUE)
			return TCAPI_ERR_MEDIA_NOT_OPEN;

		m_lastCommError = GetLastError();
		err = TCAPI_ERR_COMM_ERROR;

		PROCLOGOPEN();
		PROCLOGA1("CRealSerialComm::PollPort ClearCommError failed=%d\n", m_lastCommError);
//		if (m_lastCommError > 0)
		LogErrorText2(m_lastCommError);
		PROCLOGCLOSE();
	}
	else
	{
		// ClearCommError succeeded
		if (lclErrorFlags)
		{
			m_lastCommError = lclErrorFlags;
			err = TCAPI_ERR_COMM_ERROR;
			PROCLOGOPEN();
			PROCLOGA1("CRealSerialComm::PollPort ClearCommError succeeded but lclErrorFlags=%d\n", m_lastCommError);
			PROCLOGCLOSE();
		}
		else
		{
//			DUMPCOMSTATP(&lclComStat);
//			PROCLOGOPEN();
//			PROCLOGA1("CRealSerialComm::PollPort ClearCommError succeeded cbInQue=%d\n", lclComStat.cbInQue);
//			PROCLOGCLOSE();
			m_lastCommError = 0;
		}
		outSize = lclComStat.cbInQue;
	}

	return err;
}
#ifdef _DEBUG
void CRealSerialComm::DumpComStat(COMSTAT* stat)
{
	COMMLOGOPEN();
	COMMLOGA3(" comstat fCtsHold =%d fDsrHold =%d fRlsdHold=%d\n", stat->fCtsHold, stat->fDsrHold, stat->fRlsdHold);
	COMMLOGA3(" comstat fXoffHold=%d fXoffSent=%d fEof     =%d\n", stat->fXoffHold, stat->fXoffSent, stat->fEof);
	COMMLOGA3(" comstat fTxim    =%d cbInQue  =%d cbOutQue =%d\n", stat->fTxim, stat->cbInQue, stat->cbOutQue);
	COMMLOGCLOSE();
}
void CRealSerialComm::DumpComStatP(COMSTAT* stat)
{
	PROCLOGOPEN();
	PROCLOGA3(" comstat fCtsHold =%d fDsrHold =%d fRlsdHold=%d\n", stat->fCtsHold, stat->fDsrHold, stat->fRlsdHold);
	PROCLOGA3(" comstat fXoffHold=%d fXoffSent=%d fEof     =%d\n", stat->fXoffHold, stat->fXoffSent, stat->fEof);
	PROCLOGA3(" comstat fTxim    =%d cbInQue  =%d cbOutQue =%d\n", stat->fTxim, stat->cbInQue, stat->cbOutQue);
	PROCLOGCLOSE();
}
#endif
long CRealSerialComm::ReadPort(DWORD inSize, void *outData, DWORD &outSize)
{
	long err = TCAPI_ERR_NONE;
	outSize = 0;

	COMSTAT lclComStat;
	DWORD lclErrorFlags=0;
	DWORD lclLength;
	if (!IsConnected())
		return TCAPI_ERR_MEDIA_NOT_OPEN;

	// clear out any errors in the channel and get the length of the buffer
	if (!ClearCommError( m_hSerial, &lclErrorFlags, &lclComStat ))
	{
		// ClearCommError failed
		m_lastCommError = GetLastError();
		err = TCAPI_ERR_COMM_ERROR;
		PROCLOGOPEN();
		PROCLOGA1("CRealSerialComm::ReadPort ClearCommError failed=%d\n", m_lastCommError);
		PROCLOGCLOSE();
	}
	else
	{
		if (lclErrorFlags)
		{
			m_lastCommError = lclErrorFlags;
			err = TCAPI_ERR_COMM_ERROR;
			PROCLOGOPEN();
			PROCLOGA1("CRealSerialComm::ReadPort ClearCommError succeeded but lclErrorFlags=%d\n", m_lastCommError);
			PROCLOGCLOSE();
		}
		else
		{
			m_lastCommError = 0;

			lclLength = min( inSize, lclComStat.cbInQue );

			if (lclLength > 0)
			{
				// Read lclLength number of bytes into outData.
				if (!ReadFile(m_hSerial,outData,lclLength,&outSize,NULL))
				{
					m_lastCommError = GetLastError();
					err = TCAPI_ERR_COMM_ERROR;
					PROCLOGOPEN();
					PROCLOGA1("CRealSerialComm::ReadPort ReadFile failed = %d\n", m_lastCommError);
					PROCLOGCLOSE();
				}
				else
				{
					// ReadFile returned successful, check to see all our bytes came in
					//  If a timeout happened - we may not get all the data
					if (lclLength != outSize)
					{
						lclErrorFlags = 0;
						if (!ClearCommError( m_hSerial, &lclErrorFlags, &lclComStat ))
						{
							// ClearCommError failed
							m_lastCommError = GetLastError();
							err = TCAPI_ERR_COMM_ERROR;
							PROCLOGOPEN();
							PROCLOGA1("CRealSerialComm::ReadPort ClearCommError failed=%d\n", m_lastCommError);
							PROCLOGCLOSE();
						}
						else
						{
							// ClearCommError succeeded
							if (lclErrorFlags)
							{
								// there really was an error
								m_lastCommError = lclErrorFlags;
								err = TCAPI_ERR_COMM_ERROR;
								PROCLOGOPEN();
								PROCLOGA1("CRealSerialComm::ReadPort ReadFile succeeded-not all data read lclErrorFlags=%d\n", m_lastCommError);
								PROCLOGCLOSE();
							}
							else
							{
								// Since we are not doing overlapped I/O 
								//  and our timeout values say to timeout, we should read all the bytes
								//  that the last Poll told us, if not this is an error
								err = TCAPI_ERR_COMM_ERROR;
								PROCLOGOPEN();
								PROCLOGS("CRealSerialComm::ReadPort ReadFile succeeded-not all data read lclErrorFlags=0\n");
								PROCLOGCLOSE();
							}
						}
					}
					else
					{
						// all data read
						m_lastCommError = 0;
						PROCLOGOPEN();
						PROCLOGS("CRealSerialComm::ReadPort ReadFile successful\n");
						PROCLOGCLOSE();
					}
				}
			}
		}
	}

	return err;
}

long CRealSerialComm::ProcessBuffer(CConnection* pConn, CRegistry* pRegistry, long& numberProcessed)
{
	PROCLOGOPEN();
	PROCLOGS("CRealSerialComm::ProcessBuffer\n");
	PROCLOGCLOSE();

	long err = TCAPI_ERR_NONE;
	long routingErr = TCAPI_ERR_NONE;

	if (!IsConnected())
		return TCAPI_ERR_MEDIA_NOT_OPEN;

	if (!m_Protocol)
		return TCAPI_ERR_UNKNOWN_MEDIA_TYPE;

	DWORD protocolHeaderLength = m_Protocol->GetHeaderLength();

	// fill buffer
	if (m_numberBytes < MAX_SERIAL_MESSAGE_BUFFER_LENGTH)
	{
		DWORD outLen = 0;
		err = PollPort(outLen);
		if (err == TCAPI_ERR_NONE && outLen > 0)
		{
			if (outLen > (MAX_SERIAL_MESSAGE_BUFFER_LENGTH - m_numberBytes))
				outLen = MAX_SERIAL_MESSAGE_BUFFER_LENGTH - m_numberBytes;
			BYTE *ptr = &m_pBuffer[m_numberBytes];
			err = ReadPort(outLen, ptr, outLen);
			if (err == TCAPI_ERR_NONE && outLen > 0)
			{
				m_numberBytes += outLen;
			}
		}
	}
	// now process buffer but only for complete messages
	if (err == TCAPI_ERR_NONE)
	{
		if (m_numberBytes >= protocolHeaderLength)
		{
			BYTE* ptr = m_pBuffer;
			long bytesRemaining = m_numberBytes;
			long usedLen = 0;
			bool done = false;
			long numberSkipped=0;

			while (!done)
			{
				DWORD fullMessageLength = bytesRemaining;
				DWORD rawLength = 0;
				BYTE* fullMessage = ptr;
				BYTE* rawMessage = ptr;
				BYTE msgId = 0;
				int result = m_Protocol->DecodeMessage(fullMessage, fullMessageLength, msgId, rawMessage, rawLength);
				if (result == DECODE_NOT_ENOUGH_BYTES_TO_SEARCH)
				{
					done = true;
				}
				else if (result == DECODE_MESSAGE_NOT_FOUND)
				{
					numberSkipped++;
					usedLen += fullMessageLength;
					bytesRemaining -= fullMessageLength;
					ptr += fullMessageLength;
					if (bytesRemaining < protocolHeaderLength)
						done = true;
				}
				else if (result == DECODE_MESSAGE_FOUND)
				{
					err = PreProcessMessage(msgId, fullMessageLength, fullMessage);
					if (err != TCAPI_ERR_NONE)
					{
						PROCLOGOPEN();
						PROCLOGA1("CTcpComm::ProcessBuffer Notify err = %x\n", err);
						PROCLOGCLOSE();
						// notify all clients right now 
						pConn->NotifyClientsCommError(err, false, 0);
						err = TCAPI_ERR_NONE;
					}
#ifdef _DEBUG
					int reallen = fullMessageLength;
					if (reallen > 80) reallen = 80;
					char msg[6];
					msg[0] = '\0';

					sLogMsg[0] = '\0';
					if (reallen > 0)
					{
						sLogMsg[0] = '\0';
						for (int i = 0; i < reallen; i++)
						{
							if (isalnum(ptr[i]))
							{
								sprintf(msg, "%c", ptr[i]);
							}
							else
							{
								sprintf(msg, "%02.2x ", ptr[i]);
							}
							strcat(sLogMsg, msg);
						}
					}
#endif
					PROCLOGOPEN();
					PROCLOGA5("CRealSerialComm::ProcessBuffer - RouteMesssage pRegistry = %x id=%x len=%d len=%d msg=%s\n", pRegistry, msgId, fullMessageLength, rawLength, sLogMsg);
					PROCLOGCLOSE();

					err = pRegistry->RouteMessage(msgId, fullMessage, fullMessageLength, rawMessage, rawLength);
					if (err != TCAPI_ERR_NONE) routingErr = err; // saved for future

					numberProcessed++;
					usedLen += fullMessageLength;
					bytesRemaining -= fullMessageLength;
					ptr += fullMessageLength;
					if (bytesRemaining < protocolHeaderLength)
						done = true;
				}
			}
			DeleteMsg(usedLen);
		}
	}
//	PROCLOGOPEN();
//	PROCLOGA1("CRealSerialComm::ProcessBuffer err = %d\n", err);
//	PROCLOGCLOSE();
	if (routingErr == TCAPI_ERR_NONE)
		return err;
	else
		return routingErr;
}
bool CRealSerialComm::IsConnectionEqual(ConnectData* pConn)
{
	bool equal = false;

	// forms accepted:
	//   "comNN", "NN"
	char* ptr1 = m_ConnectSettings->realSerialSettings.comPort;
	char* ptr2 = pConn->realSerialSettings.comPort;
	bool digit1found = false;
	while(!digit1found && *ptr1 != NULL) 
	{
		if (*ptr1 >= '0' && *ptr1 <= '9')
		{
			digit1found = true;
			break;
		}
		ptr1++;
	}
	bool digit2found = false;
	while(!digit2found && *ptr2 != NULL) 
	{
		if (*ptr2 >= '0' && *ptr2 <= '9')
		{
			digit2found = true;
			break;
		}
		ptr2++;
	}
	if (digit1found && digit2found)
	{
		if (strcmp(ptr1, ptr2) == 0)
			equal = true;
	}
	return equal;
}

#ifdef _DEBUG
DWORD CRealSerialComm::GetErrorText(DWORD inError)
{
	LPVOID lpMsgBuf;
	
	if (inError == 0) return inError;

	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL,
		inError,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 	// Default language
		(LPTSTR) &lpMsgBuf,
		0,
		NULL );

	COMMLOGA1(" -- GetErrorText=%s", lpMsgBuf);
	// Free the buffer.
	LocalFree( lpMsgBuf );
	
	return inError;
}
DWORD CRealSerialComm::GetErrorText2(DWORD inError)
{
	LPVOID lpMsgBuf;
	
	if (inError == 0) return inError;

	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL,
		inError,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 	// Default language
		(LPTSTR) &lpMsgBuf,
		0,
		NULL );

	PROCLOGA1(" -- GetErrorText=%s", lpMsgBuf);
	// Free the buffer.
	LocalFree( lpMsgBuf );
	
	return inError;
}

void CRealSerialComm::DumpBuffer(BYTE* ptr, long length)
{
	char msg[256] = {0};
	if (length > 50) length = 50;
	for (int i = 0; i < length; i++)
	{
		sprintf(msg, "%s%02.2X ", msg, ptr[i]);
	}
	sprintf(msg, "%s\n", msg);
	PROCLOGS(msg);
}
#endif