|
// CSeries.cpp: implementation of the CCSeries class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SeriesComm.h"
#include "CSeries.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
const CM_THREADCOMMWRITE = WM_USER + 110;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CCSeries::CCSeries()
{
m_hComm = INVALID_HANDLE_VALUE;
}
CCSeries::~CCSeries()
{
}
BOOL CCSeries::WritePort(HANDLE hComm, const BYTE *buf, DWORD bufLen)
{
DWORD dwNumBytesWritten = 0;
DWORD dw_HaveNumWritten = 0;
ASSERT(hComm != INVALID_HANDLE_VALUE);
//清空串口
PurgeComm(hComm,PURGE_RXCLEAR | PURGE_TXCLEAR);
do
{
if(WriteFile(hComm,buf + dw_HaveNumWritten,bufLen - dw_HaveNumWritten,&dwNumBytesWritten,NULL))
{
dw_HaveNumWritten = dw_HaveNumWritten + dwNumBytesWritten;
//写入完成
if (dw_HaveNumWritten == bufLen)
{
break;
}
Sleep(10);
}
else
{
AfxMessageBox(_T("write failed."));
return FALSE;
}
}while(TRUE);
return TRUE;
}
//串口读线程函数
DWORD WINAPI CCSeries::ReadThreadFunc(LPVOID lparam)
{
CCSeries *ceSeries = (CCSeries*)lparam;
DWORD evtMask;
BYTE * readBuf = NULL; //读取的字节
DWORD actualReadLen = 0; //实际读取的字节数
DWORD WillReadLen;
DWORD dwReadErrors;
COMSTAT cmState;
//清空缓冲,并检查串口是否打开
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);
while(TRUE)
{
if (WaitCommEvent(ceSeries->m_hComm,&evtMask,0))
{
//延时50毫秒再读数据
Sleep(30);
// CCSeries::Count += 1;
SetCommMask(ceSeries->m_hComm,EV_RXCHAR | EV_CTS | EV_DSR);
//表示串口接收到字符
if ((evtMask & EV_RXCHAR) == EV_RXCHAR)
{
ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
WillReadLen = cmState.cbInQue;
if (WillReadLen <=0)
{
continue;
}
readBuf = new BYTE[WillReadLen];
ReadFile(ceSeries->m_hComm,readBuf,WillReadLen,&actualReadLen,0);
//读取的数据大于0
if (actualReadLen > 0)
{
//触发回调函数
ceSeries->m_OnSeriesRead(ceSeries->m_pPortOwner,readBuf,actualReadLen);
}
//清空串口
PurgeComm(ceSeries->m_hComm,PURGE_RXCLEAR | PURGE_TXCLEAR);
delete [] readBuf;
}
}
//如果收到读线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,500) == WAIT_OBJECT_0)
{
break;
}
}
return 0;
}
//串口写线程函数
DWORD WINAPI CCSeries::WriteThreadFunc(LPVOID lparam)
{
CCSeries *ceSeries = (CCSeries*)lparam;
MSG msg;
DWORD dwWriteLen = 0;
BYTE * buf = NULL;
while(TRUE)
{
if (PeekMessage(&msg,0,0,0,PM_REMOVE))
{
if (msg.hwnd != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (msg.message == CM_THREADCOMMWRITE)
{
buf = (BYTE*) msg.lParam;
dwWriteLen = msg.wParam;
WritePort(ceSeries->m_hComm,buf,dwWriteLen);
delete[] buf;
}
}
//如果收到写线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hWriteCloseEvent,500) == WAIT_OBJECT_0)
{
break;
}
ceSeries->m_hWriteThread = NULL;
}
return 0;
}
//关闭读线程
void CCSeries::CloseReadThread()
{
SetEvent(m_hReadCloseEvent);
//设置所有事件无效
SetCommMask(m_hComm,0);
//清空所有将要读的数据
PurgeComm(m_hComm,PURGE_RXCLEAR);
if (WaitForSingleObject(m_hReadThread,10000) == WAIT_TIMEOUT)
{
TerminateThread(m_hReadThread,0);
}
m_hReadThread = NULL;
}
//关闭写线程
void CCSeries::CloseWriteThread()
{
SetEvent(m_hWriteCloseEvent);
//设置所有事件无效
SetCommMask(m_hComm,0);
//清空所有将要读的数据
PurgeComm(m_hComm,PURGE_TXCLEAR);
if (WaitForSingleObject(m_hWriteThread,10000) == WAIT_TIMEOUT)
{
TerminateThread(m_hWriteThread,0);
}
m_hWriteThread = NULL;
}
BOOL CCSeries::OpenPort(CWnd *pProtOwner, UNIT portno, UNIT baud, UNIT parity, UNIT databits, UNIT stopbits)
{
DCB commParam;
TCHAR szPort[15];
if (m_hComm != INVALID_HANDLE_VALUE)
{
return TRUE;
}
ASSERT(pProtOwner != NULL);
ASSERT(portno > 0 && portno < 5);
//设置串口名
wsprintf(szPort,L"COM%d:",portno);
//打开串口
m_hComm = CreateFile(szPort,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if (m_hComm == INVALID_HANDLE_VALUE)
{
AfxMessageBox(_T("无法打开端口!请检查是否已被占用。"));
return FALSE;
}
//得到打开串口的当前属性参数,修改后再重新设置串口
//设置串口的超时 特性为立即返回
if (!GetCommState(m_hComm,&commParam))
{
AfxMessageBox(_T("GetCommState faild."));
return FALSE;
}
commParam.BaudRate = baud;
commParam.fBinary = TRUE;//设置二进制模式,此处必须设置为true
commParam.fParity = TRUE;//支持奇偶校验
commParam.ByteSize = databits;
commParam.Parity = NOPARITY;
commParam.StopBits = stopbits;
commParam.fOutxCtsFlow = FALSE;
commParam.fOutxDsrFlow = FALSE;
commParam.fDtrControl = DTR_CONTROL_ENABLE;
commParam.fDsrSensitivity = FALSE;
commParam.fTXContinueOnXoff = 0;
commParam.fOutX = 0;
commParam.fInX = 0;
commParam.ErrorChar = FALSE;
commParam.fNull = FALSE;
commParam.fRtsControl = RTS_CONTROL_ENABLE;
commParam.fAbortOnError = FALSE;
if (!SetCommState(m_hComm,&commParam))
{
AfxMessageBox(_T("SetCommState error."));
return FALSE;
}
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts(m_hComm,&CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout = 100;
CommTimeOuts.ReadTotalTimeoutMultiplier = 1;
CommTimeOuts.ReadTotalTimeoutConstant = 100;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(m_hComm,&CommTimeOuts))
{
AfxMessageBox(_T("无法按当前参数配置端口,请检查参数!"));
return FALSE;
}
m_pPortOwner = pProtOwner;
SetCommMask(m_hComm,EV_RXCHAR);
SetupComm(m_hComm,1024,1024);
PurgeComm(m_hComm,PURGE_TXCLEAR | PURGE_RXCLEAR);
m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
if (NULL == m_hReadCloseEvent)
{
AfxMessageBox(_T("Create read close event failed."));
return FALSE;
}
m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
if (NULL == m_hWriteCloseEvent)
{
AfxMessageBox(_T("Create write close event failed."));
return FALSE;
}
m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);
if (NULL == m_hReadThread)
{
AfxMessageBox(_T("Create read thread failed."));
return FALSE;
}
m_hWriteThread = CreateThread(NULL,0,WriteThreadFunc,this,0,&m_dwWriteThreadID);
if (NULL == m_hWriteThread)
{
AfxMessageBox(_T("Create write thread failed."));
return FALSE;
}
return TRUE;
}
//关闭串口
void CCSeries::ClosePort()
{
if (m_hComm == INVALID_HANDLE_VALUE)
{
return;
}
CloseReadThread();
CloseWriteThread();
if (!CloseHandle(m_hComm))
{
m_hComm = INVALID_HANDLE_VALUE;
return;
}
}
BOOL CCSeries::WritePort(const BYTE *buf, DWORD bufLen)
{
if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,WPARAM(bufLen),LPARAM(buf)))
{
return TRUE;
}
return FALSE;
}
BOOL CCSeries::SetSeriesTimeOuts(COMMTIMEOUTS CommTimeOuts)
{
ASSERT(m_hComm != INVALID_HANDLE_VALUE);
return SetCommTimeouts(m_hComm,&CommTimeOuts);
}
|
|