简单封装的串口通信类

#include "stdafx.h"

#include "SerialPort.h"



#include "assert.h"



CSerialPort::CSerialPort()

{

    memset(&m_OverlappedRead, 0, sizeof(m_OverlappedRead));

    memset(&m_OverlappedWrite, 0, sizeof(m_OverlappedWrite));

    m_bOpened = false;

    m_ReadComThread = NULL;

    m_hIDCom = NULL;

    m_dwReadLen = 0;

}



CSerialPort::~CSerialPort()

{



}



BOOL CSerialPort::OpenPort(UINT nPort, UINT nBaud)

{

    ASSERT(nPort > 0 && nPort < 5);  

    if(m_bOpened)

        return true;

    

    TCHAR szPort[15];

    TCHAR szComParams[50];

    DCB dcb;



    wsprintf(szPort, _T("COM%d"), nPort);

    m_hIDCom = ::CreateFile(szPort, 

        GENERIC_READ | GENERIC_WRITE, 

        0, 

        NULL,

        OPEN_EXISTING,

        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,

        NULL);

    if(m_hIDCom == NULL)

        return false;



    memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));

    memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));



    COMMTIMEOUTS CommTimeOuts;

    CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;

    CommTimeOuts.ReadTotalTimeoutConstant = 0;

    CommTimeOuts.ReadTotalTimeoutMultiplier = 0;

    CommTimeOuts.WriteTotalTimeoutMultiplier = 0;

    CommTimeOuts.WriteTotalTimeoutConstant = 5000;

    ::SetCommTimeouts(m_hIDCom, &CommTimeOuts);



    wsprintf(szComParams, _T("COM%d:%d,N,8,1"), nPort, nBaud);

    m_OverlappedRead.Offset = 0;

    m_OverlappedRead.OffsetHigh = 0;

    m_OverlappedRead.hEvent = ::CreateEvent(NULL, true, false, NULL);

    m_OverlappedWrite.Offset = 0;

    m_OverlappedWrite.OffsetHigh = 0;

    m_OverlappedWrite.hEvent = ::CreateEvent(NULL, true, false, NULL);



    dcb.DCBlength = sizeof(DCB);

    ::GetCommState(m_hIDCom, &dcb);

    dcb.BaudRate = nBaud;

    dcb.ByteSize = 8;

    dcb.Parity = 0;



    if(!SetCommState(m_hIDCom, &dcb) || !SetupComm(m_hIDCom, 4096, 4096) ||

        m_OverlappedRead.hEvent == NULL || m_OverlappedWrite.hEvent == NULL)

    {

        DWORD dwError = ::GetLastError();

        if(m_OverlappedRead.hEvent != NULL)

            ::CloseHandle(m_OverlappedRead.hEvent);

        if(m_OverlappedWrite.hEvent != NULL)

            ::CloseHandle(m_OverlappedWrite.hEvent);

        ::CloseHandle(m_hIDCom);

        return false;

    }

    ::SetCommMask(m_hIDCom, EV_RXCHAR);

    ::PurgeComm(m_hIDCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

    ::EscapeCommFunction(m_hIDCom, SETDTR);



    m_bOpened =true;

    m_bExitThread =false;



    StartMonitoring();

    return m_bOpened;

}



BOOL CSerialPort::Close()

{

    if(!m_bOpened || m_hIDCom == NULL)

        return true;

    m_bExitThread = true;

    ::SetCommMask(m_hIDCom, 0);

    StopMonitoring();

    

    if(m_OverlappedRead.hEvent != NULL)

        ::CloseHandle(m_OverlappedRead.hEvent);



    if(m_OverlappedWrite.hEvent != NULL)

        ::CloseHandle(m_OverlappedWrite.hEvent);



    ::CloseHandle(m_hIDCom);



    m_bOpened = false;

    m_hIDCom = NULL;



    return true;

}





//向串口写数据

void CSerialPort::WriteToPort(BYTE *Byte, int Len)

{

    if(!m_bOpened || m_hIDCom == NULL)

        return;



    BOOL bWriteStat;

    DWORD dwBytesWritten;

    ClearReadBuf();

    bWriteStat = ::WriteFile(m_hIDCom, Byte, Len, &dwBytesWritten, &m_OverlappedWrite);



    if(!bWriteStat && (::GetLastError() == ERROR_IO_PENDING))

    {

        //WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就

        //返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,

        //否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。

        DWORD dw = ::WaitForSingleObject(m_OverlappedWrite.hEvent, INFINITE );

        if(dw == WAIT_TIMEOUT)

        {

            dwBytesWritten = 0;

            DCB dcb;

            ::GetCommState(m_hIDCom, &dcb);

            ::PurgeComm(m_hIDCom, PURGE_TXCLEAR);

            return;

        }

        else

        {

            ::GetOverlappedResult(m_hIDCom, &m_OverlappedWrite, &dwBytesWritten, false);//等待服务器完成IO操作

            m_OverlappedWrite.Offset += dwBytesWritten;

        }

    }

    return ;

}





//从串口读取数据

int CSerialPort::ReadFromPort(BYTE *lpszBlock, int nRLen)

{

    if(!m_bOpened || m_hIDCom == NULL)

        return 0;



    BOOL bReadStat;

    DWORD dwBytesRead, dwErrorFlags;

    COMSTAT ComStat;

    ::ClearCommError(m_hIDCom, &dwErrorFlags, &ComStat);

    if(!ComStat.cbInQue)

        return 0;



    dwBytesRead = (DWORD) ComStat.cbInQue;

    if(nRLen < (int)dwBytesRead)

        dwBytesRead = (DWORD) nRLen;



    bReadStat = ::ReadFile(m_hIDCom, lpszBlock, dwBytesRead, &dwBytesRead, &m_OverlappedRead);

    if(!bReadStat)

    {

        if(::GetLastError() == ERROR_IO_PENDING)

        {

            ::WaitForSingleObject(m_OverlappedRead.hEvent, INFINITE);

            return (int)dwBytesRead;

        }

        return 0;

    }

    return (int)dwBytesRead;

}







UINT CSerialPort::CommThread(LPVOID pParam)

{

    CSerialPort* pSerialPort = (CSerialPort*)pParam;

    BYTE Buffer[4096];

    DWORD dwEvent, dwError;

    COMSTAT ComStat;

    int ReadLen = 0;

    memset(pSerialPort->m_ReadBuf, '\0', sizeof(pSerialPort->m_ReadBuf));

    ::SetCommMask(pSerialPort->m_hIDCom, EV_RXCHAR);

    while(!pSerialPort->m_bExitThread)

    {

        memset(Buffer, '\0', 4096);

        ::WaitCommEvent(pSerialPort->m_hIDCom, &dwEvent, NULL);

        ::ClearCommError(pSerialPort->m_hIDCom, &dwError, &ComStat);

        if((dwEvent & EV_RXCHAR) && ComStat.cbInQue)

        {

            pSerialPort->m_dwReadLen = pSerialPort->ReadFromPort(Buffer,4096);

            pSerialPort->m_dwReadLen = ReadLen >4096 ? 4096 : ReadLen;

            if(pSerialPort->m_dwReadLen > 0)

            {

                memcpy(pSerialPort->m_ReadBuf, Buffer,pSerialPort->m_dwReadLen);

            }

        }

        ::PurgeComm(pSerialPort->m_hIDCom, PURGE_RXCLEAR);

    }

    return 0;

}



BOOL CSerialPort::StartMonitoring()

{

    if(m_ReadComThread == NULL)

    {

        if(!(m_ReadComThread = ::AfxBeginThread(CommThread, this)))

            return false;

    }

    return true;

}



BOOL CSerialPort::StopMonitoring()

{

    if(m_ReadComThread != NULL)

    {

        ::TerminateThread(m_ReadComThread->m_hThread, 0); //终结线程

        m_ReadComThread = NULL;

    }

    return true;

}



void CSerialPort::ClearReadBuf()

{

    memset(m_ReadBuf, '\0', sizeof(m_ReadBuf));

    m_dwReadLen = 0;

}

你可能感兴趣的:(通信)