You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

592 lines
14 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 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 sizebuffer的大小
返回值:
备注:
修改记录: 日期: 作者: 备注:
-----------------------------------------------------------------------------*/
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;
}