分享一个简洁实用的C++串口类CxComm

    添加时间:2013-7-6 点击量:

      这是我在实际工作中设计的一个C++串口类,类名、函数名和变量名均采取匈牙利定名法。小写的x代表我的姓氏首字母(谢欣能),小我习惯罢了,如有类似,纯属偶合。


     CxComm的定义如下:



    #define        MAX_COMM_BUFFER              4096
    
    #define DEF_COMM_INPUT_BUFFER 8192

    class XIO_CLASS CxComm
    {
    public:
    CxComm();
    virtual ~CxComm();

    public:
    BOOL Open(LPCSTR lpszPort);
    BOOL Listen();
    BOOL Close();
    void SetWindowMessage(MSG pMsg, WNDPROC wndproc = NULL)
    {
    m_msg
    = pMsg;
    m_wndproc
    = wndproc;
    }
    HANDLE GetSafeHandle() {
    return m_hComm; }
    void GetCommPort(LPSTR lpszPort) { strcpy(lpszPort, m_szComm); }

    void SetRThreshold(BYTE btRThreshold) { m_btRThreshold = btRThreshold; }
    BYTE GetRThreshold() {
    return m_btRThreshold; }

    BOOL GetSettings(LPDCB lpdcb);
    BOOL SetSettings(LPDCB lpdcb);

    BOOL GetBufferSize(LPDWORD lpdwInSize, LPDWORD lpdwOutSize);
    BOOL SetBufferSize(DWORD dwInSize, DWORD dwOutSize);
    BOOL GetBufferCount(LPDWORD lpdwInSize, LPDWORD lpdwOutSize);
    BOOL ClearBuffer(BOOL bInput);

    BOOL Receive(LPBYTE lpbtData, DWORD dwSize);
    BOOL Send(LPBYTE lpbtData, DWORD dwSize);
    void SelectEvent(long lEvent) { m_dwEvent = lEvent; }

    protected:
    void DisListen();
    static DWORD WINAPI ListenProc(LPVOID lpParam);
    void OnListen();

    private:
    char m_szComm[FIX_SERIALCOMM];
    HANDLE m_hComm;
    HANDLE m_hThreadListen, m_hEventListen;
    BOOL m_bExitThreadListen;
    BYTE m_btRThreshold;
    DWORD m_dwInBuffSize, m_dwOutBuffSize, m_dwEvent;
    MSG m_msg;
    WNDPROC m_wndproc;
    };


      因为这个类被我封装在动态库里面,所以类名前应用了导出标记XIO_CLASS,读者在应用时完全可以去掉。别的,FIX_SERIALCOMM是一个定义为8的宏,来自对另一个头文件的引用(将来的文章会向大师介绍)。这个类的定义被我放在一个包含很多类定义的头文件中,没有零丁为它写头文件,所以它的定义项目组代码看上去没有高低文。


      CxComm的实现如下:



    // xComm.cpp: implementation of the CxComm class.
    
    //
    //////////////////////////////////////////////////////////////////////

    #include
    stdafx.h
    #include
    ../xio.h
    #include
    <stdio.h>

    //////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////

    CxComm::CxComm()
    : m_hComm(NULL)
    , m_hThreadListen(NULL)
    , m_hEventListen(NULL)
    , m_dwEvent(EV_RXCHAR)
    , m_bExitThreadListen(TRUE)
    , m_btRThreshold(
    1
    , m_dwInBuffSize(MAX_COMM_BUFFER)
    , m_dwOutBuffSize(MAX_COMM_BUFFER)
    , m_wndproc(NULL)
    {
    ZeroMemory(m_szComm,
    sizeof(m_szComm));
    ZeroMemory(
    &m_msg, sizeof(m_msg));
    }

    CxComm::
    ~CxComm()
    {

    }

    BOOL CxComm::Open(LPCSTR lpszPort)
    {
    if ((lpszPort == NULL) || (lpszPort[0] == \0))
    return FALSE;

    Close();

    HANDLE hCom
    = CreateFile(lpszPort, GENERIC_READ | GENERIC_WRITE, 0
    NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (hCom == INVALID_HANDLE_VALUE)
    return FALSE;

    strcpy(m_szComm, lpszPort);
    m_hComm
    = hCom;

    DWORD dwError;
    COMSTAT cs
    = {0};
    ClearCommError(m_hComm,
    &dwError, &cs);

    return TRUE;
    }

    BOOL CxComm::Listen()
    {
    if (m_hComm == NULL)
    return FALSE;

    if (m_hThreadListen != NULL)
    return FALSE;

    SetCommMask(m_hComm, m_dwEvent);
    m_bExitThreadListen
    = FALSE;
    DWORD dwExitCode;
    m_hThreadListen
    = CreateThread(NULL, 0, ListenProc, this0, &dwExitCode);

    return (m_hThreadListen != NULL);
    }

    void CxComm::DisListen()
    {
    if (m_hThreadListen != NULL)
    {
    m_bExitThreadListen
    = TRUE;
    SetEvent(m_hEventListen);

    WaitForSingleObject(m_hThreadListen, INFINITE);
    CloseHandle(m_hThreadListen);
    m_hThreadListen
    = NULL;
    }
    }

    BOOL CxComm::Close()
    {
    BOOL bRet
    = TRUE;
    if (m_hComm != NULL)
    {
    DisListen();

    ClearBuffer(TRUE);
    ClearBuffer(FALSE);
    CloseHandle(m_hComm);
    m_hComm
    = NULL;
    ZeroMemory(m_szComm,
    sizeof(m_szComm));
    }

    m_wndproc
    = NULL;

    return bRet;
    }

    BOOL CxComm::GetSettings(LPDCB lpdcb)
    {
    if (m_hComm == NULL)
    return FALSE;

    return GetCommState(m_hComm, lpdcb);
    }

    BOOL CxComm::SetSettings(LPDCB lpdcb)
    {
    if (m_hComm == NULL)
    return FALSE;

    return SetCommState(m_hComm, lpdcb);
    }

    BOOL CxComm::GetBufferSize(LPDWORD lpdwInSize, LPDWORD lpdwOutSize)
    {
    if (m_hComm == NULL)
    return FALSE;

    COMMPROP cp
    = {0};
    if (!GetCommProperties(m_hComm, &cp))
    return FALSE;

    if (lpdwInSize != NULL)
    lpdwInSize = cp.dwCurrentRxQueue;

    if (lpdwOutSize != NULL)
    lpdwOutSize = cp.dwCurrentTxQueue;

    return TRUE;
    }

    BOOL CxComm::SetBufferSize(DWORD dwInSize, DWORD dwOutSize)
    {
    if (m_hComm == NULL)
    return FALSE;

    return SetupComm(m_hComm, dwInSize, dwOutSize);
    }

    BOOL CxComm::GetBufferCount(LPDWORD lpdwInSize, LPDWORD lpdwOutSize)
    {
    if (m_hComm == NULL)
    return FALSE;

    DWORD dwError;
    COMSTAT cs
    = {0};

    if (!ClearCommError(m_hComm, &dwError, &cs))
    return FALSE;

    if (lpdwInSize != NULL)
    lpdwInSize = cs.cbInQue;

    if (lpdwOutSize != NULL)
    lpdwOutSize = cs.cbOutQue;

    return TRUE;
    }

    BOOL CxComm::ClearBuffer(BOOL bInput)
    {
    if (m_hComm == NULL)
    return FALSE;

    DWORD dwFlag
    = bInput ? PURGE_RXCLEAR : PURGE_TXCLEAR;
    return PurgeComm(m_hComm, dwFlag);
    }

    BOOL CxComm::Send(LPBYTE lpbtData, DWORD dwSize)
    {
    if (m_hComm == NULL)
    return FALSE;

    DWORD dwWritten
    = 0, dwToWrite, dwRet;
    BOOL bRet;
    OVERLAPPED o
    = {0};
    char szEvent[MAX_EVENT];
    sprintf(szEvent,
    %d.%s.Send, (DWORD)this, m_szComm);

    // asynchronous
    while (dwWritten != dwSize)
    {
    dwToWrite
    = dwSize - dwWritten;
    o.hEvent
    = CreateEvent(NULL, TRUE, FALSE, szEvent);
    bRet
    = WriteFile(m_hComm, &lpbtData[dwWritten], dwToWrite, NULL, &o);
    if (!bRet)
    {
    dwRet
    = GetLastError();
    if (ERROR_IO_PENDING == dwRet)
    WaitForSingleObject(o.hEvent, INFINITE);
    }
    CloseHandle(o.hEvent);
    dwWritten
    += o.InternalHigh;
    }

    return TRUE;
    }

    BOOL CxComm::Receive(LPBYTE lpbtData, DWORD dwSize)
    {
    if (m_hComm == NULL)
    return FALSE;

    ZeroMemory(lpbtData, dwSize);
    DWORD dwReaded
    = 0, dwToRead, dwRet;
    BOOL bRet;
    OVERLAPPED o
    = {0};
    char szEvent[MAX_EVENT];
    sprintf(szEvent,
    %d.%s.Recv, (DWORD)this, m_szComm);

    // asynchronous
    while (dwReaded != dwSize)
    {
    dwToRead
    = dwSize - dwReaded;
    o.hEvent
    = CreateEvent(NULL, TRUE, FALSE, szEvent);
    bRet
    = ReadFile(m_hComm, &lpbtData[dwReaded], dwToRead, NULL, &o);
    if (!bRet)
    {
    dwRet
    = GetLastError();
    if (ERROR_IO_PENDING == dwRet)
    WaitForSingleObject(o.hEvent, INFINITE);
    }
    CloseHandle(o.hEvent);
    dwReaded
    += o.InternalHigh;
    }

    return TRUE;
    }

    DWORD WINAPI CxComm::ListenProc(LPVOID lpParam)
    {
    DWORD dwID
    = ::GetCurrentThreadId();
    char szDebug[MAX_PATH];
    sprintf(szDebug,
    The thread 0 x%X(CxComm::ListenProc) has entered.\n, dwID);
    OutputDebugString(szDebug);

    CxComm
    pThis = (CxComm)lpParam;
    if (pThis != NULL)
    pThis
    ->OnListen();

    sprintf(szDebug,
    The thread 0 x%X(CxComm::ListenProc) has exited.\n, dwID);
    OutputDebugString(szDebug);

    return 0;
    }

    void CxComm::OnListen()
    {
    OVERLAPPED o
    = {0};
    COMSTAT cs
    = {0};
    DWORD dwEvtMask, dwError;
    BOOL bRet;
    char szEvent[MAX_EVENT];
    sprintf(szEvent,
    %s.Listen, m_szComm);

    while (!m_bExitThreadListen)
    {
    m_hEventListen
    = CreateEvent(NULL, TRUE, FALSE, szEvent);
    o.hEvent
    = m_hEventListen;

    bRet
    = WaitCommEvent(m_hComm, &dwEvtMask, &o);
    if (!bRet)
    {
    dwError
    = GetLastError();
    if (ERROR_IO_PENDING == dwError)
    WaitForSingleObject(m_hEventListen, INFINITE);
    }

    if (dwEvtMask & m_dwEvent)
    {
    if (m_dwEvent & EV_RXCHAR) // 今朝只通知缓冲区有输入
    {
    if (ClearCommError(m_hComm, &dwError, &cs))
    {
    if (cs.cbInQue >= m_btRThreshold)
    {
    if (m_wndproc != NULL)
    m_wndproc(m_msg.hwnd, m_msg.message,
    (WPARAM)m_hComm, (LPARAM)EV_RXCHAR);
    else
    SendMessage(m_msg.hwnd, m_msg.message,
    (WPARAM)m_hComm, (LPARAM)EV_RXCHAR);
    }
    }
    }
    }

    CloseHandle(m_hEventListen);
    m_hEventListen
    = NULL;
    }
    }


      这个类的实现项目组的代码不久不多,抛开VC6领导生成的一段,统共200多行。实现了设备串口、读写串口以及侦听串口的功能,还有以两种体式格式通知上层法度处理惩罚串口数据的功能。别的,侦听串口启动了一个新的线程,不会让界面线程梗阻的。


      我写的很多实用类都很是简洁,一般都没有注释,有也是中英文混搭两句,大师习惯就好。To be continued...

    读书,不要想着实用,更不要有功利心。读书只为了自身的修养。邂逅一本好书如同邂逅一位知己,邂逅一个完美之人。有时心生敬意,有时怦然心动。仿佛你心底埋藏多年的话,作者替你说了出来,你们在时光深处倾心相遇的一瞬间,情投意合,心旷神怡。
    分享到: