// Serial.cpp: implementation of the CSerial class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Serial.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/*-----------------------------------------------------------------------------
prototype declaration
-----------------------------------------------------------------------------*/
DWORD WINAPI ReadThreadFunc(LPVOID para);
DWORD WINAPI WriteThreadFunc(LPVOID para);

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

/*-----------------------------------------------------------------------------
FUNCTION:	CSerial()
PURPOSE:	Construction
COMMENTS:	
HISTORY:	Date:		Author:		Comment:
-----------------------------------------------------------------------------*/
CSerial::CSerial()
{
	m_bIsInitialized=FALSE;
	m_hExitReadThreadEvent=NULL;
	m_hExitWriteThreadEvent=NULL;
	m_hComHandle=NULL;
	m_hReadCompletedEvent=NULL;
	m_hWriteCompletedEvent=NULL;
	m_hReadThread=NULL;
	m_hWriteThread=NULL;
	m_hStartWriteEvent=NULL;
	memset(out_buffer,0,MAX_OUT_BUFFER);
	memset(in_buffer,0,MAX_IN_BUFFER);
	ReadCallBack=NULL;
	InitializeCriticalSection(&m_csReadSection);
	InitializeCriticalSection(&m_csWriteSection);
}

/*-----------------------------------------------------------------------------
FUNCTION:	~CSerial()
PURPOSE:	Destruction
COMMENTS:	
HISTORY:	Date:		Author:		Comment:
-----------------------------------------------------------------------------*/
CSerial::~CSerial()
{
	DeInit();
	DeleteCriticalSection(&m_csReadSection);
	DeleteCriticalSection(&m_csWriteSection);
}

/*-----------------------------------------------------------------------------
����ԭ��:	DWORD WINAPI ReadThreadFunc(LPVOID para)
Ŀ��:		�������̺߳���
����:		LPVOID para,����������̵߳IJ���,ΪPDATA_PACKAGE��
����ֵ:		DWORD �ͣ������̷߳���
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
DWORD WINAPI ReadThreadFunc(LPVOID para)
{
	CSerial*pSerial=(CSerial*)para;
	OVERLAPPED osReader={0};
	HANDLE hArray[2];
	BOOL	bThreadOn=TRUE;
	BOOL	bWaitingOnRead=FALSE;
	DWORD	dwRes;
	osReader.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	hArray[0]=osReader.hEvent;
	hArray[1]=pSerial->m_hExitReadThreadEvent;
	while(bThreadOn)
	{
		EnterCriticalSection(&(pSerial->m_csReadSection));
		if(!bWaitingOnRead)
		{
			if(!ReadFile(pSerial->m_hComHandle,pSerial->in_buffer,MAX_IN_BUFFER,&(pSerial->m_dwRead),&osReader))
			{
				if(GetLastError()!=ERROR_IO_PENDING)
				{
					bThreadOn=FALSE;
				}
				else
				{
					bWaitingOnRead=TRUE;
				}
			}
			else
			{
				if(pSerial->m_dwRead>0)
				{
					pSerial->HandleSuccessRead();
				}
			}
		}
		if(bWaitingOnRead)
		{
			dwRes=WaitForMultipleObjects(2,hArray,FALSE,100);
			switch(dwRes)
			{
			case WAIT_OBJECT_0:
				if(!GetOverlappedResult(pSerial->m_hComHandle,&osReader,&(pSerial->m_dwRead),FALSE))
				{
					bThreadOn=FALSE;
				}
				else
				{
					if(pSerial->m_dwRead>0)
					{
						pSerial->HandleSuccessRead();
					}
				}
				bWaitingOnRead=FALSE;
				ResetEvent(osReader.hEvent);
				break;
			case WAIT_OBJECT_0+1:
				bThreadOn=FALSE;
				break;
			case WAIT_TIMEOUT:
				break;
			default:
				bThreadOn=FALSE;
				break;
			}
		}
		LeaveCriticalSection(&(pSerial->m_csReadSection));
	}
	CloseHandle(osReader.hEvent);
	return 0;
}

/*-----------------------------------------------------------------------------
����ԭ��:	DWORD WINAPI WriteThreadFunc(LPVOID para)
Ŀ��:		д�����̺߳���
����:		LPVOID para,����д�����̵߳IJ���,ΪPDATA_PACKAGE��
����ֵ:		DWORD �ͣ������̷߳���
��ע:	
�޸ļ�¼:	����:		����:		��ע:
07/01/05	��־ΰ		�������ԭ��
08/25/05	��־ΰ		��������ͬ�����룬
��ֹ���ݱ�ͬʱ�޸�
-----------------------------------------------------------------------------*/
DWORD WINAPI WriteThreadFunc(LPVOID para)
{
	CSerial*pSerial=(CSerial*)para;
	OVERLAPPED osWriter={0};
	BOOL	bThreadOn=TRUE;
	BOOL	bWaitingOnWrite=FALSE;
	DWORD	dwRes;
	HANDLE	hArray[3];
	osWriter.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	hArray[0]=pSerial->m_hStartWriteEvent;
	hArray[1]=osWriter.hEvent;
	hArray[2]=pSerial->m_hExitWriteThreadEvent;

	while(bThreadOn)
	{
		dwRes=WaitForMultipleObjects(3,hArray,FALSE,CHECK_TIMEOUT);
		EnterCriticalSection(&(pSerial->m_csWriteSection));
		switch(dwRes)
		{
		case WAIT_OBJECT_0:
			DWORD dd;
			if(!WriteFile(pSerial->m_hComHandle,pSerial->out_buffer,pSerial->m_dwToWrite,&dd,&osWriter))
			{
				if(GetLastError()!=ERROR_IO_PENDING)
				{
					bThreadOn=FALSE;
				}				
			}
			ResetEvent(pSerial->m_hStartWriteEvent);
			break;
		case WAIT_OBJECT_0+1:
			if(!GetOverlappedResult(pSerial->m_hComHandle,&osWriter,&pSerial->m_dwWritten,FALSE))
			{
				bThreadOn=FALSE;
			}
			else
			{
				SetEvent(pSerial->m_hWriteCompletedEvent);				
			}
			ResetEvent(osWriter.hEvent);
			break;
		case WAIT_OBJECT_0+2:
			bThreadOn=FALSE;
			break;
		case WAIT_TIMEOUT:
			break;
		default:
			bThreadOn=FALSE;
			break;
		}
		LeaveCriticalSection(&(pSerial->m_csWriteSection));
	}
	CloseHandle(osWriter.hEvent);
	return 0;
}

/*-----------------------------------------------------------------------------
����ԭ��:	BOOL CSerial::Initialize(char *serial_port, 
DWORD baud_rate,
BYTE byte_size,
BYTE parity,
BYTE stopbits)
Ŀ��:		��ʼ������
����:		char*serial_port,���ַ�����ʾ�Ĵ�������
DWORD baud_rate,������
BYTE  byte_size,�������
BYTE parity ,������
BYTE stopbits,ֹͣλ����
����ֵ:		BOOL �ͣ������Ƿ��ʼ���ɹ�
��ע:	
�޸ļ�¼:	����:		����:		��ע:char *serial_port,
-----------------------------------------------------------------------------*/
BOOL CSerial::Initialize(PCTSTR serial_port,
	DWORD baud_rate/*=CBR_9600*/,
	BYTE byte_size/*=8*/,
	BYTE parity/*=PARITY_NONE*/,
	BYTE stopbits/*=ONESTOPBIT*/)
{
	if(m_bIsInitialized)
		DeInit();

	TCHAR name[256];
	_tcscpy(name, _T("\\\\.\\"));
	_tcscat(name, serial_port);

	m_hComHandle=CreateFile(name,
		GENERIC_READ|GENERIC_WRITE,
		0,
		0,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
		0);

	if(INVALID_HANDLE_VALUE==m_hComHandle)
	{
		DeInit();
		return FALSE;
	}
	DCB dcb;
	if(!GetCommState(m_hComHandle,&dcb))
	{
		DeInit();
		return FALSE;
	}
	dcb.BaudRate=baud_rate;
	dcb.ByteSize=byte_size;
	dcb.Parity=parity;
	dcb.StopBits=stopbits;
	if(!SetCommState(m_hComHandle,&dcb))
	{
		DeInit();
		return FALSE;
	}
	COMMTIMEOUTS timeout;
	timeout.ReadIntervalTimeout=5;
	timeout.ReadTotalTimeoutConstant=0;
	timeout.ReadTotalTimeoutMultiplier=0;
	timeout.WriteTotalTimeoutConstant=0;
	timeout.WriteTotalTimeoutMultiplier=0;
	if(!SetCommTimeouts(m_hComHandle,&timeout))
	{
		DeInit();
		return FALSE;
	}
	if(!RestartReadThread())
	{
		DeInit();
		return FALSE;
	}
	if(!RestartWriteThread())
	{
		DeInit();
		return FALSE;
	}
	m_bIsInitialized=TRUE;
	return TRUE;
}

/*-----------------------------------------------------------------------------
����ԭ��:	BOOL CSerial::DeInit()
Ŀ��:		�Ͽ�����
����:		
����ֵ:		
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
void CSerial::DeInit()
{
	ExitReadThread();
	ExitWriteThread();
	if(m_hComHandle!=NULL)
	{
		CloseHandle(m_hComHandle);
		m_hComHandle=NULL;
	}
	m_bIsInitialized=FALSE;
}

/*-----------------------------------------------------------------------------
����ԭ��:	BOOL CSerial::ExitReadThread()
Ŀ��:		�˳��������߳�
����:		
����ֵ:		
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
void CSerial::ExitReadThread()
{
	if(m_hReadThread!=NULL)
	{
		SetEvent(m_hExitReadThreadEvent);
		Sleep(300);
		if(m_hReadThread!=NULL)
		{	
			CloseHandle(m_hReadThread);
			m_hReadThread=NULL;
		}
	}	
	if(m_hExitReadThreadEvent!=NULL)
	{
		CloseHandle(m_hExitReadThreadEvent);
		m_hExitReadThreadEvent=NULL;
	}
	if(m_hReadCompletedEvent!=NULL)
	{
		SetEvent(m_hReadCompletedEvent);
		Sleep(200);
		if(m_hReadCompletedEvent!=NULL)
		{
			CloseHandle(m_hReadCompletedEvent);
			m_hReadCompletedEvent=NULL;
		}
	}
}

/*-----------------------------------------------------------------------------
����ԭ��:	BOOL CSerial::RestartReadThread()
Ŀ��:		�����������߳�
����:		
����ֵ:		BOOL �ͣ������Ƿ�ɹ�
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
BOOL CSerial::RestartReadThread()
{
	PurgeComm(m_hComHandle, PURGE_RXCLEAR);
	m_hExitReadThreadEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	if(m_hExitReadThreadEvent==NULL)
	{
		ExitReadThread();
		return FALSE;
	}
	m_hReadCompletedEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	if(m_hReadCompletedEvent==NULL)
	{
		ExitReadThread();
		return FALSE;
	}
	m_hReadThread=CreateThread(NULL,
		0,
		ReadThreadFunc,
		this,
		NULL,
		&m_dwReadProcID);
	if(m_hReadThread==NULL)
	{
		ExitReadThread();
		return FALSE;
	}
	return TRUE;
}

/*-----------------------------------------------------------------------------
����ԭ��:	BOOL CSerial::RestartWriteThread()
Ŀ��:		����д�����߳�
����:		
����ֵ:		BOOL �ͣ������Ƿ�ɹ�
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
BOOL CSerial::RestartWriteThread()
{
	PurgeComm(m_hComHandle, PURGE_TXCLEAR);
	m_hStartWriteEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	if(m_hStartWriteEvent==NULL)
	{
		DeInit();
		return FALSE;
	}
	m_hExitWriteThreadEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	if(m_hExitWriteThreadEvent==NULL)
	{
		DeInit();
		return FALSE;
	}
	m_hWriteCompletedEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	if(m_hWriteCompletedEvent==NULL)
	{
		DeInit();
		return FALSE;
	}

	m_hWriteThread=CreateThread(NULL,
		0,
		WriteThreadFunc,
		this,
		NULL,
		&m_dwWriteProcID);
	if(m_hWriteThread==NULL)
	{
		DeInit();
		return FALSE;
	}
	return TRUE;
}

/*-----------------------------------------------------------------------------
����ԭ��:	BOOL CSerial::ExitWriteThread()
Ŀ��:		�ر�д�����߳�
����:		
����ֵ:		
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
void CSerial::ExitWriteThread()
{
	if(m_hWriteThread!=NULL)
	{
		SetEvent(m_hExitWriteThreadEvent);
		Sleep(200);
		if(m_hWriteThread!=NULL)
		{
			CloseHandle(m_hWriteThread);
			m_hWriteThread=NULL;
		}
	}
	if(m_hExitWriteThreadEvent!=NULL)
	{
		CloseHandle(m_hExitWriteThreadEvent);
		m_hExitWriteThreadEvent=NULL;
	}
	if(m_hWriteCompletedEvent!=NULL)
	{
		SetEvent(m_hWriteCompletedEvent);
		Sleep(200);
		if(m_hWriteCompletedEvent!=NULL)
		{
			CloseHandle(m_hWriteCompletedEvent);
			m_hWriteCompletedEvent=NULL;
		}
	}
	if(m_hStartWriteEvent!=NULL)
	{
		CloseHandle(m_hStartWriteEvent);
		m_hStartWriteEvent=NULL;
	}
}

/*-----------------------------------------------------------------------------
����ԭ��:	HANDLE* CSerial::GetWriteCompletedEvent() const
Ŀ��:		�õ�д��������¼����
����:	
����ֵ:		HANDLE* �ͣ�д��������¼����
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
HANDLE* CSerial::GetWriteCompletedEvent() const
{
	return (HANDLE*)&m_hWriteCompletedEvent;
}

/*-----------------------------------------------------------------------------
����ԭ��:	HANDLE* CSerial::GetReadCompletedEvent() const
Ŀ��:		�õ�����������¼����
����:	
����ֵ:		HANDLE* �ͣ�����������¼����
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
HANDLE *CSerial::GetReadCompletedEvent() const
{
	return (HANDLE*)&m_hReadCompletedEvent; 
}

/*-----------------------------------------------------------------------------
����ԭ��:	void CSerial::WriteABuffer(char *buffer, DWORD size)
Ŀ��:		ͨ���������ⷢ������
����:		char*buffer,�����͵�����
DWORD	size��buffer�Ĵ�С
����ֵ:		
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
void CSerial::WriteABuffer(unsigned char *buffer, DWORD size)
{
	EnterCriticalSection(&m_csWriteSection);
	for(DWORD i=0;i<size;i++)
	{
		out_buffer[i]=buffer[i];
	}
	m_dwToWrite=size;
	SetEvent(m_hStartWriteEvent);
	LeaveCriticalSection(&m_csWriteSection);
}

/*-----------------------------------------------------------------------------
����ԭ��:	DWORD CSerial::ReadABuffer(char *buffer)
Ŀ��:		������������
����:		char*buffer,����������
����ֵ:		DWORD�ͣ����������ݵĴ�С
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
DWORD CSerial::ReadABuffer(char *buffer)
{
	EnterCriticalSection(&m_csReadSection);
	for(DWORD i=0;i<m_dwRead;i++)
	{
		buffer[i]=in_buffer[i];
	}
	LeaveCriticalSection(&m_csReadSection);
	return m_dwRead;
}

/*-----------------------------------------------------------------------------
����ԭ��:	void CSerial::SetComReadCallback(COMCALLBACK func)
Ŀ��:		���öԴ��ڶ������ݽ��д����Ļص�����
����:		COMCALLBACK func�����ڻص�������ַ
����ֵ:		��
��ע:	
�޸ļ�¼:	����:		����:		��ע:
-----------------------------------------------------------------------------*/
void CSerial::SetComReadCallback(COMCALLBACK func)
{
	ReadCallBack=func;
}

/*---------------------------------------------------------------------------*\
����ԭ��:	void CSerial::HandleSuccessRead()
Ŀ��:		�������ڶ��������
����:		
����ֵ:		
��ע:	
�޸ļ�¼:	����:		����:		��ע:
\*---------------------------------------------------------------------------*/
void CSerial::HandleSuccessRead()
{
	if(ReadCallBack!=NULL)
	{
		ReadCallBack(in_buffer,m_dwRead);
	}
}

/*-----------------------------------------------------------------------------
����:		��ȡ����д�߳�ID
����:		
����ֵ:		DWORD�ͣ�д�߳�ID
-----------------------------------------------------------------------------*/
DWORD CSerial::GetWriteThreadID()const
{
	return m_dwWriteProcID;
}

/*-----------------------------------------------------------------------------
����:		��ȡ���ڶ��߳�ID
����:		
����ֵ:		DWORD�ͣ����߳�ID
-----------------------------------------------------------------------------*/
DWORD CSerial::GetReadThreadID()const
{
	return m_dwReadProcID;
}

/*-----------------------------------------------------------------------------
����:		�ж��Ƿ��Ѿ������˳�ʼ��
����:		
����ֵ:		BOOL �ͣ������Ƿ��ʼ���ɹ�
-----------------------------------------------------------------------------*/
BOOL CSerial::IsInitialized()const 
{
	return m_bIsInitialized;	
}