// 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,传入读串口线程的参数,为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,传入写串口线程的参数,为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