#include "StdAfx.h"
#include "SynSerial.h"

CSynSerial::CSynSerial(void) :m_hSerialPort(NULL)
, m_dwInQueue(1024)
, m_dwOutQueue(1024)
{
	memset(&m_dcb, 0, sizeof(DCB));
	memset(&m_cts, 0, sizeof(COMMTIMEOUTS));
	memset(&m_szSerialPort, 0, sizeof(TCHAR)*MAX_PORT_LEN);
}

CSynSerial::~CSynSerial(void)
{
	CloseSerialPort();
}

BOOL CSynSerial::OpenSerialPort(IN CONST BYTE & byCommPort, IN CONST DWORD & dwBaudRate, IN CONST BYTE & bySize, IN CONST BYTE & byParity, IN CONST BYTE & byStopBits, IN CONST BYTE & byStartAddr, IN CONST INT & nInterval)
{
	ASSERT(byCommPort);
	CloseSerialPort();

	_stprintf_s(m_szSerialPort, _T("\\\\.\\com%d"), (int)byCommPort);
	m_hSerialPort = CreateFile(m_szSerialPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);
	if (m_hSerialPort == INVALID_HANDLE_VALUE)
	{
		// 打开串口失败;
		DWORD dwError = GetLastError();
		return FALSE;
	}

	BOOL bResult = FALSE;
	// SetupComm设置缓冲区大小;
	bResult = SetupComm(m_hSerialPort, m_dwInQueue, m_dwOutQueue);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// 在串口读写之前,清除缓冲区;
	bResult = PurgeComm(m_hSerialPort, PURGE_TXCLEAR | PURGE_RXCLEAR);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// GetCommState获取设备控制块状态;
	memset(&m_dcb, 0, sizeof(DCB));
	bResult = GetCommState(m_hSerialPort, &m_dcb);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	m_dcb.Parity = byParity;
	if (m_dcb.Parity == NOPARITY)
		m_dcb.fParity = FALSE;
	else
		m_dcb.fParity = TRUE;

	m_dcb.BaudRate = dwBaudRate;
	m_dcb.ByteSize = bySize;
	m_dcb.StopBits = byStopBits;
	if (m_dcb.ByteSize == 8)
		m_dcb.StopBits = ONESTOPBIT;

	// SetCommState设置设备的控制块状态;
	memset(&m_cts, 0, sizeof(COMMTIMEOUTS));
	bResult = SetCommState(m_hSerialPort, &m_dcb);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// 获取设备的超时值;
	bResult = GetCommTimeouts(m_hSerialPort, &m_cts);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// 两字符之间最大的延时,设置0表示参数不起作用;
	m_cts.ReadIntervalTimeout = 50;
	m_cts.ReadTotalTimeoutMultiplier = 100;
	m_cts.ReadTotalTimeoutConstant = 8000;
	m_cts.WriteTotalTimeoutMultiplier = 100;
	m_cts.WriteTotalTimeoutConstant = 5000;

	// 设置设备的超时值;
	bResult = SetCommTimeouts(m_hSerialPort, &m_cts);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	return TRUE;
}

BOOL CSynSerial::ReOpenSerialPort()
{
	ASSERT(_tcslen(m_szSerialPort));
	CloseSerialPort();

	m_hSerialPort = CreateFile(m_szSerialPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);
	if (m_hSerialPort == INVALID_HANDLE_VALUE)
	{
		// 打开串口失败;
		DWORD dwError = GetLastError();
		return FALSE;
	}

	BOOL bResult = FALSE;
	// SetupComm设置缓冲区大小;
	bResult = SetupComm(m_hSerialPort, m_dwInQueue, m_dwOutQueue);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// 在串口读写之前,清除缓冲区;
	bResult = PurgeComm(m_hSerialPort, PURGE_TXCLEAR | PURGE_RXCLEAR);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// SetCommState设置设备的控制块状态;
	memset(&m_cts, 0, sizeof(COMMTIMEOUTS));
	bResult = SetCommState(m_hSerialPort, &m_dcb);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// 设置设备的超时值;
	bResult = SetCommTimeouts(m_hSerialPort, &m_cts);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	return TRUE;
}

void CSynSerial::CloseSerialPort()
{
	if (m_hSerialPort != NULL && m_hSerialPort != INVALID_HANDLE_VALUE)
		CloseHandle(m_hSerialPort);
	m_hSerialPort = NULL;
}

BOOL CSynSerial::SetSerialPort(IN CONST DWORD & dwBaudRate, IN CONST BYTE & byByteSize, IN CONST BYTE & byParity, IN CONST BYTE & byStopBits, IN CONST BYTE & byStartAddr, IN CONST DWORD & dwInQueue, IN CONST DWORD & dwOutQueue)
{
	if (!IsOpen())
		return FALSE;

	BOOL bResult = FALSE;
	// GetCommState获取设备控制块状态;
	memset(&m_dcb, 0, sizeof(DCB));
	bResult = GetCommState(m_hSerialPort, &m_dcb);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	m_dcb.Parity = byParity;
	if (m_dcb.Parity == NOPARITY)
		m_dcb.fParity = FALSE;
	else
		m_dcb.fParity = TRUE;

	m_dcb.BaudRate = dwBaudRate;
	m_dcb.ByteSize = byByteSize;
	m_dcb.StopBits = byStopBits;
	if (m_dcb.ByteSize == 8)
		m_dcb.StopBits = ONESTOPBIT;

	// SetCommState设置设备的控制块状态;
	memset(&m_cts, 0, sizeof(COMMTIMEOUTS));
	bResult = SetCommState(m_hSerialPort, &m_dcb);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// 获取设备的超时值;
	bResult = GetCommTimeouts(m_hSerialPort, &m_cts);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	// 两字符之间最大的延时,设置0表示参数不起作用;
	m_cts.ReadIntervalTimeout = 50;
	m_cts.ReadTotalTimeoutMultiplier = 100;
	m_cts.ReadTotalTimeoutConstant = 8000;
	m_cts.WriteTotalTimeoutMultiplier = 100;
	m_cts.WriteTotalTimeoutConstant = 3000;

	// 设置设备的超时值;
	bResult = SetCommTimeouts(m_hSerialPort, &m_cts);
	if (!bResult)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}

	return TRUE;
}

void CSynSerial::SetSerialDCB(IN CONST DCB & dcb)
{
}

void CSynSerial::SetSerialCommTimeouts(IN CONST COMMTIMEOUTS & commTimeouts)
{
}

DWORD CSynSerial::WriteComm(IN BYTE * pWirteBuf, IN CONST INT32 nWriteSize)
{
	if (!IsOpen())
		return 0;

	if (pWirteBuf == NULL || !::AfxIsValidAddress(pWirteBuf, nWriteSize, FALSE))
	{
		return 0;
	}
	
	DWORD dwErrorFlags;
	DWORD dwBytesWritten = 0;	// 实际写入的字节数;
	// 写前, 清除错误;
	COMSTAT ComStat;
	ClearCommError(m_hSerialPort, &dwErrorFlags, &ComStat);	
	// 写前,清空缓存区;
	PurgeComm(m_hSerialPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
	if ( !WriteFile(m_hSerialPort, pWirteBuf, nWriteSize, &dwBytesWritten, NULL) )
	{
		DWORD dwError = GetLastError();
	}	

	// 返回写入字节数;
	return dwBytesWritten;
}

DWORD CSynSerial::ReadComm(IN BYTE * pReadBuf, IN CONST DWORD & dwReadSize)
{
	if (!IsOpen())
		return 0;

	if (pReadBuf == NULL || !::AfxIsValidAddress(pReadBuf, dwReadSize, FALSE))
	{
		return 0;
	}

	DWORD dwBytesRead = 0;
	DWORD dwErrorFlags = 0;
	// ReadFile前，使用ClearCommError清除错误;
	COMSTAT ComStat = {0};
	DWORD dwLastLen = 0;
	ULONGLONG ulTick = GetTickCount64();	
	// 直到有数据为止，超时3秒;
	while (true)
	{// cbInQue表示输入缓冲区的字节数; 
		Sleep(300);
		if (GetTickCount64() - ulTick > 3000)
			break;
		ClearCommError(m_hSerialPort, &dwErrorFlags, &ComStat);
		// 防止读一次没读完，再读一次;二次长度一样表示读完;
		if (ComStat.cbInQue != 0 && dwLastLen == ComStat.cbInQue)
			break;
		dwLastLen = ComStat.cbInQue;
	}

	if (ComStat.cbInQue == 0)
	{
		// 串口超时，无数据返回;
		return 0;
	}

	dwBytesRead = ComStat.cbInQue;
	if (dwReadSize < dwBytesRead)
	{
		dwBytesRead = dwReadSize;
	}

	if (ReadFile(m_hSerialPort, pReadBuf, dwBytesRead, &dwBytesRead, NULL))
	{
		return (INT)dwBytesRead;
	}

	return dwBytesRead;
}

void CSynSerial::SetTimeouts(COMMTIMEOUTS& timeouts)
{
	ASSERT(IsOpen());
	if (!SetCommTimeouts(m_hSerialPort, &timeouts))
	{
		DWORD dwLastError = GetLastError();
	}
}