#pragma once
typedef void(CALLBACK* ONCOMMREAD)(void* i_pOwner,const BYTE* i_buf, DWORD dwBufLen);
class BaseComm
{
public:
BaseComm(void);
virtual ~BaseComm(void);
bool open(void* i_pOwner, UINT i_nPortNo,UINT i_nBaudRate, UINT i_nByteSize, UINT i_nStopBits, UINT i_nParity);
bool close();
bool setTimeOuts(COMMTIMEOUTS i_CommTimeOuts);
bool isOpen();
bool write(const BYTE* i_pData, int i_nLength); //写操作
bool write(const CString& i_szData);
void setReadFun(ONCOMMREAD i_pReadFun); //设置读操作
private:
static DWORD WINAPI ReadThread(LPVOID i_lparam);
CString getError();
ONCOMMREAD m_OnReadEvent; //读操作函数地址
HANDLE m_hComm; //串口句柄
HANDLE m_hReadThread; //读线程句柄
DWORD m_dwReadThreadID; //读线程ID
HANDLE m_hReadCloseEvent; //读线程退出事件
bool m_bOpened; //串口状态
void* m_pOwner; //使用者
};
/
#include "StdAfx.h"
#include "WinCE500.h"
#include "BaseComm.h"
/* 用法
#define WM_RECV_DATA WM_USER+101
static void CALLBACK OnReadEvent(void* i_pOwner,const BYTE* i_buf, DWORD i_bufLen);
afx_msg LONG OnRecv(WPARAM wParam,LPARAM lParam);
void CALLBACK CommDlg::OnReadEvent(void* i_pOwner,const BYTE* i_buf, DWORD i_bufLen)
{
BYTE* pRecvBuf = NULL;
CGPS_CommDlg* pThis = (CGPS_CommDlg*)i_pOwner;
pRecvBuf = new BYTE[i_bufLen];
CopyMemory(pRecvBuf,i_buf,i_bufLen);
pThis->PostMessage(WM_RECV_DATA,WPARAM(pRecvBuf),i_bufLen);
}
LONG CommDlg::OnRecv(WPARAM wParam,LPARAM lParam)
{
CString strOldRecv = L"";
CString strRecv = L"";
CHAR* pBuf = (CHAR*)wParam;
DWORD dwBufLen = lParam;
strRecv = CString(pBuf);
delete[] pBuf;
pBuf = NULL;
return 0;
}
if( !m_commTest.open(this,7,38400,8,ONE5STOPBITS,NOPARITY))
{
MessageBox(L"Failed to openComm!");
m_commTest.close();
}
//m_commTest.m_OnReadEvent = OnReadEvent;
m_commTest.setReadFun(OnReadEvent);
/----------- 备注 ------------
回调函数必须是静态成员函数或者全局函数. 用回调函数的好处: 可以在完全不知客户情
况下独立实现编译代码。 如果采取直接调用的方式, 那么想实现编译,总是必须定义好
客户的类型,这样,生产者和客户就不能完全独立开了。
回调函数其实并不神秘,不过是保存了一个指向函数的函数指针, 把函数当指针用时,函
数在编译时不再是函数,而是一个四字节的变量了,所以不影响编译。
可用静态成员函数,成员函数,拥有者,提供的数据来实现回调函数与C++的联接问题。
*/
DWORD BaseComm::ReadThread(LPVOID i_lparam)
{
BaseComm* pBaseComm = (BaseComm*)i_lparam;
DWORD evtMask;
BYTE* readBuf = NULL;
DWORD actualReadLen = 0;
DWORD willReadLen;
DWORD dwReadErrors;
COMSTAT cmState;
assertDebug(INVALID_HANDLE_VALUE != pBaseComm->m_hComm,pBaseComm->getError());
PurgeComm(pBaseComm->m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR);
SetCommMask(pBaseComm->m_hComm,EV_RXCHAR|EV_CTS|EV_DSR);
while( TRUE)
{
if( WaitCommEvent(pBaseComm->m_hComm,&evtMask,0))
{
SetCommMask(pBaseComm->m_hComm,EV_RXCHAR|EV_CTS|EV_DSR);
ClearCommError(pBaseComm->m_hComm,&dwReadErrors,&cmState);
willReadLen = cmState.cbInQue;
if( willReadLen <= 0)
continue;
readBuf = new BYTE[willReadLen];
ZeroMemory(readBuf,willReadLen);
ReadFile(pBaseComm->m_hComm,readBuf,willReadLen,&actualReadLen,0);
if( actualReadLen > 0)
{
if( NULL != pBaseComm->m_OnReadEvent)
{
pBaseComm->m_OnReadEvent(pBaseComm->m_pOwner,readBuf,actualReadLen);
}
}
delete[] readBuf;
readBuf = NULL;
}
if( WAIT_OBJECT_0 == WaitForSingleObject(pBaseComm->m_hReadCloseEvent,500))
{
break;
}
}
return 0;
}
BaseComm::BaseComm(void)
{
m_hComm = INVALID_HANDLE_VALUE;
m_OnReadEvent = NULL;
m_pOwner = NULL;
m_bOpened = 0;
}
BaseComm::~BaseComm(void)
{
if( m_bOpened)
{
close();
}
}
bool BaseComm::open(void* i_pOwner, UINT i_nPortNo,
UINT i_nBaudRate, UINT i_nByteSize,
UINT i_nStopBits, UINT i_nParity)
{
DCB commParam;
TCHAR szPort[15];
assertDebug(NULL != i_pOwner,L"Failed to open!");
m_pOwner = i_pOwner;
if( INVALID_HANDLE_VALUE != m_hComm)
return true;
wsprintf(szPort,L"COM%d:",i_nPortNo);
m_hComm = CreateFile(szPort,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if( INVALID_HANDLE_VALUE == m_hComm)
{
assertDebug(false,L"Failed to open!");
return false;
}
if( !GetCommState(m_hComm,&commParam))
{
assertDebug(false,L"Failed to open!");
close();
return false;
}
commParam.BaudRate = i_nBaudRate;
commParam.fBinary = TRUE;
commParam.fParity = TRUE;
commParam.ByteSize = i_nByteSize;
commParam.Parity = i_nParity;
commParam.StopBits = i_nStopBits;
commParam.fOutxCtsFlow = FALSE;
commParam.fOutxDsrFlow = FALSE;
commParam.fDtrControl = DTR_CONTROL_ENABLE;
commParam.fDsrSensitivity = FALSE;
commParam.fTXContinueOnXoff = TRUE;
commParam.fOutX = FALSE;
commParam.fInX = FALSE;
commParam.fErrorChar = FALSE;
commParam.fNull = FALSE;
commParam.fRtsControl = RTS_CONTROL_ENABLE;
commParam.fAbortOnError = FALSE;
if( !SetCommState(m_hComm,&commParam))
{
assertDebug(false,L"Failed to open!");
close();
return false;
}
COMMTIMEOUTS i_CommTimeOuts;
GetCommTimeouts(m_hComm,&i_CommTimeOuts);
i_CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
i_CommTimeOuts.ReadTotalTimeoutConstant = 0;
i_CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
i_CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
i_CommTimeOuts.WriteTotalTimeoutConstant = 1000;
if( !SetCommTimeouts(m_hComm,&i_CommTimeOuts))
{
assertDebug(false,L"Failed to open!");
close();
return false;
}
SetCommMask(m_hComm,EV_RXCHAR);
SetupComm(m_hComm,512,512);
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
CString strEvent;
strEvent.Format(L"ComReadCloseEvent%d",i_nPortNo);
m_hReadCloseEvent =CreateEvent(NULL,TRUE,FALSE,strEvent);
m_hReadThread = CreateThread(NULL,0,ReadThread,this,0,&m_dwReadThreadID);
m_bOpened = true;
return true;
}
bool BaseComm::close()
{
SetEvent(m_hReadCloseEvent);
SetCommMask(m_hComm,0);
PurgeComm(m_hComm,PURGE_RXCLEAR);
if( WAIT_TIMEOUT == WaitForSingleObject(m_hReadThread,4000))
TerminateThread(m_hReadThread,0);
m_hReadThread = NULL;
CloseHandle(m_hComm);
CloseHandle(m_hReadCloseEvent);
m_hComm = INVALID_HANDLE_VALUE;
m_OnReadEvent = NULL;
m_hReadCloseEvent = NULL;
m_bOpened = false;
return true;
}
bool BaseComm::write(const BYTE* i_pData, int i_nLength)
{
DWORD dwNumBytesWritten;
DWORD dwHaveNumWritten = 0;
int iInc = 0;
assertDebug(INVALID_HANDLE_VALUE != m_hComm,L"Failed to write!");
do
{
if( WriteFile(m_hComm,
i_pData+dwHaveNumWritten,
i_nLength-dwHaveNumWritten,
&dwNumBytesWritten,
NULL))
{
dwHaveNumWritten = dwHaveNumWritten+dwNumBytesWritten;
if( dwHaveNumWritten == i_nLength)
break;
iInc++;
if( iInc >= 3)
return false;
Sleep(10);
}
else
return false;
}while(1);
return true;
}
bool BaseComm::write(const CString& i_szData)
{
CString szDate = i_szData;
char *pchAddr = NULL;
pchAddr = UnicodToeChar(szDate);
int iLen = strlen(pchAddr);
bool bRet = write((BYTE*)pchAddr,iLen);
deleteHeapData(pchAddr);
return bRet;
}
bool BaseComm::setTimeOuts(COMMTIMEOUTS i_CommTimeOuts)
{
if( INVALID_HANDLE_VALUE == m_hComm)
{
assertDebug(false,L"Failed to setTimeOuts!");
return false;
}
if( SetCommTimeouts(m_hComm,&i_CommTimeOuts))
return true;
return false;
}
bool BaseComm::isOpen()
{
return m_bOpened;
}
CString BaseComm::getError()
{
CString strError;
strError.Format(_T("Error No.=%d"), GetLastError());
return strError;
}
void BaseComm::setReadFun(ONCOMMREAD i_pReadFun)
{
m_OnReadEvent = i_pReadFun;
}