Thursday, October 14, 2010

RS232 - Serial Port


/**********************************************************************
Description:CSerPort class compiled in Win32 - C++ environments.
Used for writing and reading the data with RS232 COMM port.
Derive further if you want add your specific features.
**********************************************************************/

class CSerPort
{
private:
    HANDLE m_hPort;
    DWORD m_dwBaud;
    BYTE m_iByteSize;
    BYTE m_iStopBits;
    BOOL m_bParity;
    CString m_strPort;
    BOOL m_bClose;
    BOOL m_bTimeOut;
    int m_nReqTime;

public:
    inline HANDLE GetHandle() { return m_hPort; }

    CSerPort()
    {
        // default values
        m_dwBaud = CBR_9600;
        m_iByteSize = 8;
        m_iStopBits = ONESTOPBIT;
        m_bParity = FALSE;
        m_strPort = "COM1";

        m_hPort = INVALID_HANDLE_VALUE;
        m_bClose = FALSE;

        m_nReqTime = 0;
        m_bTimeOut = FALSE;
    }

    CSerPort(CString strPort,DWORD dwBaud,BYTE iByteSize,BOOL bParity, BYTE iStopBits)
    {
        m_dwBaud = dwBaud;
        m_iByteSize = iByteSize;
        m_iStopBits = iStopBits;
        m_bParity = bParity;
        m_strPort = strPort;
        m_hPort = INVALID_HANDLE_VALUE;
        m_bClose = FALSE;

        m_nReqTime = 0;
        m_bTimeOut = FALSE;

    }
    virtual ~CSerPort()
    {
        if(m_hPort != INVALID_HANDLE_VALUE)
        {
            ::CloseHandle(m_hPort);
        }
    }

    void SetPort(CString strPort) { m_strPort = strPort; }
    CString GetPort() { return m_strPort; }
    void SetBaud(DWORD dwBaud) { m_dwBaud = dwBaud; }
    DWORD GetBaud() { return m_dwBaud; }
    void SetByteSize(BYTE iByteSize) { m_iByteSize = iByteSize; }
    BYTE GetByteSize() { return m_iByteSize; }
    void SetStopBits(BYTE iStopBits) { m_iStopBits = iStopBits; }
    BYTE GetStopBits() { return m_iStopBits; }
    void SetParity(BOOL bParity) { m_bParity = bParity; }
    BOOL GetParity() { return m_bParity; }
    int GetReqTime() { return m_nReqTime; }
    BOOL GetTimeOut() { return m_bTimeOut; }

    virtual void Close() { ::CloseHandle(m_hPort); m_bClose = TRUE; }
    inline BOOL IsClosed() { return m_bClose; }

    virtual BOOL Open()
    {
        DCB devBlock;

        m_hPort = ::CreateFile(m_strPort,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);

        DWORD dw = ::GetLastError();

        if(m_hPort == INVALID_HANDLE_VALUE){
            ASSERT(FALSE);    // Unable to open port...
            return FALSE;
        }

        GetCommState(m_hPort,&devBlock);

        devBlock.ByteSize = m_iByteSize;
        devBlock.fBinary = TRUE;    
        devBlock.fParity = m_bParity;
        devBlock.StopBits = m_iStopBits;
        devBlock.BaudRate = m_dwBaud;

        ::SetCommState(m_hPort,&devBlock);

        COMMTIMEOUTS CommTimeouts;

        ::GetCommTimeouts(m_hPort, &CommTimeouts);

        // use your own timeout values all are in milliseconds
        CommTimeouts.ReadIntervalTimeout = 50;
        CommTimeouts.ReadTotalTimeoutMultiplier = 50;
        CommTimeouts.ReadTotalTimeoutConstant = 50;
        CommTimeouts.WriteTotalTimeoutMultiplier = 500;
        CommTimeouts.WriteTotalTimeoutConstant = 500;

        ::SetCommTimeouts(m_hPort, &CommTimeouts);

        ::SetCommMask(m_hPort,EV_RXCHAR);

        EscapeCommFunction(m_hPort,SETDTR);

        m_bClose = FALSE;

        return TRUE;
    }

    BOOL WriteData(BYTE* pBytes,int nBytes)
    {
        DWORD wr;
        if(m_hPort == INVALID_HANDLE_VALUE){
            ASSERT(FALSE); //Port not opened...
            return FALSE;
        }
        ::WriteFile(m_hPort,pBytes,nBytes,&wr,NULL);
        DWORD dw = ::GetLastError();


        ASSERT(wr == nBytes); // should write requested no of bytes

        return (wr == nBytes);
    }

    BOOL ReadData(BYTE* pBytes,int nBytesToRead,int nTries)
    {
        DWORD dwBytesRead = 0;
        int nTry = 0;

        BYTE* pBuff = new BYTE[nBytesToRead];
        int nBytesCopied = 0;
        while (nBytesCopied != nBytesToRead)
        {
            ::ReadFile(m_hPort,pBuff, nBytesToRead - dwBytesRead, &dwBytesRead,NULL);
            if(dwBytesRead > 0){
                ::CopyMemory(pBytes + nBytesCopied,pBuff,dwBytesRead);
                nBytesCopied += dwBytesRead;
            }

            // don't stay in the infinite loop when no data is received
            // for long time and come out with FALSE return
            if (nTry++ > nTries) {delete [] pBuff; return FALSE;}

            // this is required to allow processing of UI requests
            // when waiting for data to receive.
            MSG msg;
            if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        delete [] pBuff;
        return TRUE;
    }
};


1 comment: