/*-----------------------------------------
* Copyright (c) 2008 Eric Wong
* ����������߲ο������������κ���ҵ��Ϊ
*
* �ļ����ƣ� CESeries.cpp
* �ļ���ʶ�� 
* ժҪ�����ڷ�װWINCE ����ͨѶ
*
* ��ǰ�汾�� 1.0
* ���ߣ� ���� Eric Wong
* ������ڣ� 2008��1��17��
*
* ȡ���汾��
* ԭ���ߣ� 
* ������ڣ� 
----------------------------------------*/
#include "StdAfx.h"
#include "MySeries.h"

//���캯��
CMyCESeries::CMyCESeries(UINT portNo, UINT baud, UINT parity, UINT databits, UINT stopbits)
:m_portNo(portNo)
,m_baud(baud)
,m_parity(parity)
,m_databits(databits)
,m_stopbits(stopbits)
,m_hReadThread(NULL)
,m_hReadCloseEvent(NULL)
{
	//m_portNo		= portNo;		//���ں�ʹ�ô���1 CANģ���GPS����
	//m_baud			= baud;		//������
	//m_parity		= parity;		//��żУ��,0-None,1-Odd,2-Even
	//m_databits		= databits;		//����λ
	//m_stopbits		= stopbits;		//ֹͣλ 0-ֹͣλ1��1-ֹͣλ1.5��2-ֹͣλ2

	//��ʼ���ڲ�����
	m_hComm = INVALID_HANDLE_VALUE;
	m_OnSeriesRead = NULL;
	m_hReadCloseEvent = NULL;
	m_bOpened = false;

	bCanComRead		= true;
	m_bSyncOrAsync	= true;//ʹ��ͬ����ʽ�����첽��ʽ���ص���ʽ����Ĭ��ֵΪtrue���첽��ʽ

	memset(&m_olWrite,0,sizeof(OVERLAPPED));
}

//��������
CMyCESeries::~CMyCESeries()
{
	if (m_bOpened)
		ClosePort();
}

//���ڶ��̺߳���
DWORD CMyCESeries::ReadThreadFunc(LPVOID lparam)
{
	CMyCESeries *ceSeries = (CMyCESeries*)lparam;
	
	
	BYTE * readBuf = NULL;//��ȡ���ֽ�
	DWORD actualReadLen=0;//ʵ�ʶ�ȡ���ֽ���
	DWORD willReadLen;
	
	DWORD dwReadErrors;
	COMSTAT	cmState;
	//�첽��ʽ�½�ʹ����Щ����
	//LPOVERLAPPED 
	OVERLAPPED olWait;
	//memset(&olWaite,0,sizeof(olWaite));  
	memset(&olWait,0,sizeof(OVERLAPPED)); 
    olWait.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); 
	
	//ͬ����ʽ����ʹ�øñ���
	DWORD	 evtMask;
	


	// ��ջ��壬����鴮���Ƿ�򿪡�
	ASSERT(ceSeries->m_hComm !=INVALID_HANDLE_VALUE); 
	
	
	//��մ���
	PurgeComm(ceSeries->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR );
	
	SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );//����3�������¼�
	
	//���Բ鿴������������Щ�¼�
	//DWORD dwMask1;
	//GetCommMask(ceSeries->m_hComm,&dwMask1);

	OVERLAPPED olRead;
	memset(&olRead,0,sizeof(OVERLAPPED)); 
	olRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);


	while(TRUE)
	{
		if(ceSeries->m_bSyncOrAsync)//�첽��ʽ��
		{
			DWORD dwCommStatus = 0;
			BOOL bWait1=0;
			bWait1= WaitCommEvent(ceSeries->m_hComm,&dwCommStatus,&olWait);//����������õ�3���¼����κ�һ�������ˣ�������Ҫ�Ǽ����ջ�������������ʱ
			//while(!bWait1);//�ȴ�WaitCommEvent����ΪTRUE��������ִ�У����ַ�ʽ�в�ͨ���ص���ʽ���첽��ʽ��ʱ���ú���һֱ����Ϊfalse��
			DWORD dwByte; //norains:It is only suitable for the GetOverlappedResult(),not undefined here.
			if(GetOverlappedResult(ceSeries->m_hComm,&olWait,&dwByte,TRUE) == FALSE)//��������£���һֱ�ڸú���������ֱ��olWaite�е�hEvent�¼�������
			//��ú����������ˣ����ҷ���ֵΪTrue
			{
				 if(GetLastError() != ERROR_IO_PENDING)
				 {
					 return 0x30;
				 }
				 //Clear the error flag
				 DWORD dwErrors;
				 COMSTAT comStat;
				 memset(&comStat,0,sizeof(comStat));
				 ClearCommError(ceSeries->m_hComm,&dwErrors,&comStat);
				 return 0x35;
			}
			
				//��ʾ�����յ��ַ�		
			if (dwCommStatus & EV_RXCHAR) 
			{
				ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
				willReadLen = cmState.cbInQue ;
				if (willReadLen <= 0)
				{
					continue;
				}
				
				//�첽��ʽ
				//�����ڴ�
				readBuf = new BYTE[willReadLen+1];
				ZeroMemory(readBuf,willReadLen+1);
				//��ȡ��������

				//�첽��ʽ
				if(ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,&olRead)==FALSE)//�첽�������ڶ�ȡ����Ժ󷵻�TRUE
				{
					//�ͷ��ڴ�
					delete[] readBuf;
					readBuf = NULL;

					if(GetLastError() != ERROR_IO_PENDING)
						return 0x40;

					if(GetOverlappedResult(ceSeries->m_hComm,&olRead,&actualReadLen,TRUE) == FALSE)
						return 0x45;

					if(actualReadLen == 0)
						return 0x50;
				}
				else//�������е����ݶ�ȡ��ʱ
				{
					//�����ȡ�����ݴ���0��
					if (actualReadLen>0)
					{
						//������ȡ�ص�����
						if (ceSeries->m_OnSeriesRead)
						{
							ceSeries->m_OnSeriesRead(ceSeries->m_pOwner,readBuf,actualReadLen);
						}
					}
					//�ͷ��ڴ�
					delete[] readBuf;
					readBuf = NULL;
				}
			}
			
		}
		else//ͬ����ʽ��
		{
				if (WaitCommEvent(ceSeries->m_hComm,&evtMask,0))
				{	
					SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
					//��ʾ�����յ��ַ�
					if (evtMask & EV_RXCHAR)
					{
						ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
						willReadLen = cmState.cbInQue ;
						if (willReadLen <= 0)
						{
							continue;
						}
						
						//�����ڴ�
						readBuf = new BYTE[willReadLen];
						ZeroMemory(readBuf,willReadLen);
						//��ȡ��������
						ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
						
						//�����ȡ�����ݴ���0��
						if (actualReadLen>0)
						{
							//������ȡ�ص�����
							if (ceSeries->m_OnSeriesRead)
							{
								ceSeries->m_OnSeriesRead(ceSeries->m_pOwner,readBuf,actualReadLen);
							}
						}

						//�ͷ��ڴ�
						delete[] readBuf;
						readBuf = NULL;
					}
				}
		}

		
		
		//ÿ�ζ��߳�ִ�е��ô�ʱ������ȴ������߽�������10milseconds�����Ƿ�رմ����¼��Ƿ���
		//��ClosePort()�������е�����CloseHandle(m_hReadCloseEvent);��ʹ�ø��¼����źţ��Ҿ��ÿ�����SetEvent(m_hReadCloseEvent)���棬�ú���Ҳ��ʹ���¼����ź�
		//��ִ����ClosePotr����������˵�����¼��Ѿ������ˣ����ڶ��̺߳�����ִ�е��˴�ʱ��
		//��������while(true),�Ӷ��˳����̣߳�
		if (WaitForSingleObject(ceSeries->m_hReadCloseEvent, 10) == WAIT_OBJECT_0)//
		{
			TRACE("�߳�ReadThreadFunc�˳�\n");
			break;
		}
	}

	//�ر��¼�
	CloseHandle( olRead.hEvent );
	CloseHandle( olWait.hEvent );

	//�ͷ��ڴ�
	if(readBuf)
	{
		delete[] readBuf;
		readBuf = NULL;
	}

	ExitThread(0);
	return 0;
}

//�رն��߳�
void CMyCESeries::CloseReadThread()
{
	if( m_hComm != INVALID_HANDLE_VALUE )
	{
	//	SetEvent(m_hReadCloseEvent);
	//	CloseHandle(m_hReadCloseEvent);

		//WaitForSingleObject(m_hReadThread, 1000);

	//	DWORD exitCode;
	//	BOOL ret = GetExitCodeThread(m_hReadThread, &exitCode);
		//if(ret && exitCode != 0)
		{
			TRACE("ǿ�йر�ReadThreadFunc�߳�\n");
			TerminateThread(m_hReadThread,0);
		}
	//	CloseHandle(m_hReadThread);

		m_hReadThread = NULL;
	}

/*
	if( m_hComm != INVALID_HANDLE_VALUE )
	{
		SetEvent(m_hReadCloseEvent);
		//���������¼���Ч
		SetCommMask(m_hComm, 0);
		//������н�Ҫ��������
		PurgeComm( m_hComm,  PURGE_RXCLEAR );
		//�ȴ�4�룬������߳�û���˳�����ǿ���˳�
		if (WaitForSingleObject(m_hReadThread,4000) == WAIT_TIMEOUT)
		{
			TerminateThread(m_hReadThread,0);
		}
		m_hReadThread = NULL;
	}
//*/
}


//�������ܣ��򿪴���
//��ڲ�����pPortOwner	:ʹ�ô˴�����Ĵ�����
//		   portNo		:���ں�
//		   baud			:������
//		   parity		:��żУ��
//		   databits		:����λ
//		   stopbits		:ֹͣλ
//���ڲ�����(��)
//����ֵ��TRUE:�ɹ��򿪴���;FALSE:�򿪴���ʧ��
BOOL CMyCESeries::OpenPort(void * pOwner,
						 UINT portNo	,			//���ں�
						 UINT baud		,			//������
						 UINT parity	,			//��żУ��
						 UINT databits	,			//����λ
						 UINT stopbits  ,				//ֹͣλ
						 bool isASync
						 )
{
	m_portNo		= portNo;		//���ں�ʹ�ô���1 CANģ���GPS����
	m_baud			= baud;		//������
	m_parity		= parity;		//��żУ��,0-None,1-Odd,2-Even
	m_databits		= databits;		//����λ
	m_stopbits		= stopbits;		//ֹͣλ 0-ֹͣλ1��1-ֹͣλ1.5��2-ֹͣλ2

	m_bSyncOrAsync	= isASync;

	DCB commParam;
	TCHAR szPort[15];	

	ASSERT(pOwner!=NULL);
	m_pOwner = pOwner;
	
	// �Ѿ��򿪵Ļ���ֱ�ӷ���
	if (m_hComm != INVALID_HANDLE_VALUE)
	{
		return TRUE;
	}
	
	//������
	//wsprintf(szPort, _T("\.\COM%d:"), portNo);
	wsprintf(szPort, _T("\\\\.\\COM%d"), portNo);
	//sprintf(szPort, "\\\\.\\COM%d", portNo);
	//�򿪴���
	
	if(m_bSyncOrAsync)//m_bSyncOrAsyncֵΪ0������ͬ����ʽ�������������첽��ʽ������
	{
			m_hComm = CreateFile(			//���첽��ʽ����
			szPort,
			GENERIC_READ | GENERIC_WRITE,	//��������д
			0,								//��ռ��ʽ������ģʽ��
			NULL,
			OPEN_EXISTING,					//�򿪶����Ǵ�����������ʽ��
			 FILE_FLAG_OVERLAPPED,
			0
			);
	}
	else
	{
		m_hComm = CreateFile(			//��ͬ����ʽ����
		szPort,
		GENERIC_READ | GENERIC_WRITE,	//��������д
		0,								//��ռ��ʽ������ģʽ��
		NULL,
		OPEN_EXISTING,					//�򿪶����Ǵ�����������ʽ��
		0,  
		NULL
		);
	}


	if (m_hComm == INVALID_HANDLE_VALUE)
	{
		// ��Ч���,���ء�		
		TRACE(_T("CreateFile ���������\n"));
		DWORD  ErrNo = GetLastError();
		return FALSE;
		
	}
	
	// �õ��򿪴��ڵĵ�ǰ���Բ������޸ĺ����������ô��ڡ�
	if (!GetCommState(m_hComm,&commParam))
	{		
		//�رմ���
		CloseHandle (m_hComm);
		m_hComm = INVALID_HANDLE_VALUE;
		return FALSE;
	}

	if(m_bSyncOrAsync)//������첽��ʽ��ÿ����һ�����ڶ��󣬲��ҳɹ���һ�����ڶ���ʱ�󣬲Ŵ���һ����Ӧ�ķ����¼�
	{
		 //�첽д����     
		m_olWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,_T("WriteData"));
//		DWORD dwError = GetLastError();
//		if(dwError !=0)
//		{
//			TRACE("�첽��ʽ�������ڶ���ʱ��Ϊ�ô��ڶ�����������д�����¼�����ʧ��");
//			return FALSE;
//		}
	}
	
	//���ô��ڲ���
	commParam.BaudRate = baud;					// ������ 
	commParam.fBinary = TRUE;					// ���ö�����ģʽ���˴���������TRUE
	commParam.fParity = TRUE;					// ֧����żУ�� 
	commParam.ByteSize = databits;				// ����λ,��Χ:4-8 
	commParam.Parity = parity;					// У��ģʽ
	commParam.StopBits = stopbits;				// ֹͣλ 
	
	commParam.fOutxCtsFlow = FALSE;				// No CTS output flow control 
	commParam.fOutxDsrFlow = FALSE;				// No DSR output flow control 
	commParam.fDtrControl = DTR_CONTROL_ENABLE; 
	// DTR flow control type 
	commParam.fDsrSensitivity = FALSE;			// DSR sensitivity 
	commParam.fTXContinueOnXoff = TRUE;			// XOFF continues Tx 
	commParam.fOutX = FALSE;					// No XON/XOFF out flow control 
	commParam.fInX = FALSE;						// No XON/XOFF in flow control 
	commParam.fErrorChar = FALSE;				// Disable error replacement 
	commParam.fNull = FALSE;					// Disable null stripping 
	commParam.fRtsControl = RTS_CONTROL_ENABLE; 
	// RTS flow control 
	commParam.fAbortOnError = FALSE;			// �����ڷ������󣬲�����ֹ���ڶ�д
	
	//���ô��ڲ���
	if (!SetCommState(m_hComm, &commParam))
	{
		TRACE(_T("SetCommState error\n"));	
		DWORD dwError = GetLastError();

		//�رմ���
		CloseHandle (m_hComm);
		m_hComm = INVALID_HANDLE_VALUE;		
		return FALSE;
	}
	
    //���ô��ڶ�дʱ��
	COMMTIMEOUTS CommTimeOuts;
	GetCommTimeouts (m_hComm, &CommTimeOuts);
	CommTimeOuts.ReadIntervalTimeout = MAXDWORD;  
	CommTimeOuts.ReadTotalTimeoutMultiplier = 0;  
	CommTimeOuts.ReadTotalTimeoutConstant = 0;    
	CommTimeOuts.WriteTotalTimeoutMultiplier = 10;  
	CommTimeOuts.WriteTotalTimeoutConstant = 1000;  
	if(!SetCommTimeouts( m_hComm, &CommTimeOuts ))
	{
		TRACE( _T("SetCommTimeouts ���ش���\n") );
		//�رմ���
		CloseHandle (m_hComm);

		m_hComm = INVALID_HANDLE_VALUE;
		return FALSE;
	}
	
	//ָ���˿ڼ����¼���
	SetCommMask (m_hComm, EV_RXCHAR);
	//���䴮���豸������
	SetupComm(m_hComm,1024,1024);
	//SetupComm(m_hComm,512,512);
	//��ʼ���������е���Ϣ
	PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
	
	CString strEvent;
	strEvent.Format(_T("Com_ReadCloseEvent%d"),portNo);
	m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,strEvent);

	//�������ڶ����ݼ����߳�
	if( bCanComRead == true )
	{
		m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);//ͨ��thisָ�뽫���ڶ��󴫵ݸ����̺߳���ReadThreadFunc���β�
	}
		
	
	TRACE(_T("����%d�򿪳ɹ�\n"), portNo);
	m_bOpened = true;
	return TRUE;
}



//�������ܣ��رմ���
//��ڲ�����(��)
//���ڲ�����(��)
//����ֵ��  (��)
void CMyCESeries::ClosePort()
{	
	//��ʾ���ڻ�û�д�
	if (m_hComm == INVALID_HANDLE_VALUE)
		return ;

	//�ر��¼�
	//TRACE("�رմ��ڶ��¼�\n");	
	Sleep(100);
	//�رն��߳�
	CloseReadThread();

	//�رմ���
	TRACE("CMyCESeries�رմ���%d���\n", m_portNo);	
	CloseHandle (m_hComm);
	

	//�ر��¼�
	CloseHandle(m_olWrite.hEvent);

	m_hComm = INVALID_HANDLE_VALUE;
	m_bOpened = false;
}


//�������ܣ�������д������
//��ڲ�����buf ����д�����ݻ�����
//	       bufLen : ��д�뻺��������
//���ڲ�����(��)
//����ֵ��TRUE:���óɹ�;FALSE:����ʧ��
BOOL CMyCESeries::WriteSyncPort(const BYTE*buf , DWORD bufLen)
{
	if( false == m_bSyncOrAsync )//ͬ����ʽ
	{
		DWORD dwNumBytesWritten;
		DWORD dwHaveNumWritten =0 ; //�Ѿ�д�����
		
		int iInc = 0; //���3��д�벻�ɹ�������FALSE
		ASSERT(m_hComm != INVALID_HANDLE_VALUE);
		do
		{
			if (WriteFile (m_hComm,					//���ھ�� 
				buf+dwHaveNumWritten,				//��д���ݻ����� 
				bufLen - dwHaveNumWritten,          //��д���ݻ�������С
				&dwNumBytesWritten,					//����ִ�гɹ��󣬷���ʵ���򴮿�д�ĸ���	
				NULL))								//�˴���������NULL
			{
				dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
				//����
				if (dwHaveNumWritten == bufLen)
				{
					break;
				}
				iInc++;
				if (iInc >= 3)
				{
					TRACE("CMyCESeries::WriteSyncPort ͬ��д����ʧ��3��\n");
					return FALSE;
				}
				Sleep(10);
			}
			else
			{
				TRACE("CMyCESeries::WriteSyncPort ͬ��д����ʧ��\n");
				return FALSE;
			}
		}while (TRUE);
		
		return TRUE;	
	}
	else//�첽��ʽ
	{
		DWORD dwNumBytesWritten;
		DWORD dwHaveNumWritten =0 ; //�Ѿ�д�����

//		OVERLAPPED olWrite;
//		memset(&olWrite,0,sizeof(OVERLAPPED));
//		m_olWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,_T("WriteData"));
		 
		//�첽д����     
		if (WriteFile (m_hComm,					//���ھ�� 
						buf+dwHaveNumWritten,				//��д���ݻ����� 
						bufLen - dwHaveNumWritten,          //��д���ݻ�������С
						&dwNumBytesWritten,					//����ִ�гɹ��󣬷���ʵ���򴮿�д�ĸ���	
						&m_olWrite) == FALSE)//�����DZ�ʾд��ʧ�ܣ�����û�н���������д�뵽�������У���ֻ��д���˲��ֶ���
		{
			if(GetLastError() != ERROR_IO_PENDING)
			{
				TRACE("CMyCESeries::WriteSyncPort �첽д����0x20\n");
				return 0x20;
			}
			if(GetOverlappedResult(m_hComm,&m_olWrite,&dwNumBytesWritten,TRUE) == FALSE)//���ォһֱ������ֱ������������д�뵽������Ϊֹ
			{
				TRACE("CMyCESeries::WriteSyncPort �첽д����0x25\n");
				return 0x25;
			 }	
		}
		//else//д��ɹ�
		{
			dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
			//����
			if (dwHaveNumWritten == bufLen)
				return TRUE;
			else
			{
				TRACE("CMyCESeries::WriteSyncPort �첽д����%dʧ��\n", m_portNo);
				return FALSE;
			}
		}
	}
}


//�������ܣ����ô��ڶ�ȡ��д�볬ʱ
//��ڲ�����CommTimeOuts : ָ��COMMTIMEOUTS�ṹ
//���ڲ�����(��)
//����ֵ��TRUE:���óɹ�;FALSE:����ʧ��
BOOL CMyCESeries::SetSeriesTimeouts(COMMTIMEOUTS CommTimeOuts)
{
	ASSERT(m_hComm != INVALID_HANDLE_VALUE);
	return SetCommTimeouts(m_hComm,&CommTimeOuts);
}


//�õ������Ƿ��
BOOL CMyCESeries::GetComOpened()
{
	return m_bOpened;
}