wince 串口与回调函数

来源:互联网 发布:字典转json 去掉制表符 编辑:程序博客网 时间:2024/05/16 17:26

#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;
}