RS232 Connecter

This is a simple example to connect a RS232 device. It supports following parameters:

  • Com Port: COM1~COM11
  • Baud Rate: 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800 and 921600
  • Data Bit: 7 and 8
  • Stop Bit: 1, 1.5 and 2
  • Parity: no parity, odd, even, mark and space
  • Flow Control: hardware, Xon/Xoff and none

RS232


// RS232_ConnectionDlg.cpp : implementation file
//

#include "stdafx.h"
#include "RS232_Connection.h"
#include "RS232_ConnectionDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


struct THREAD_INFO
{
    CString csCMD;
    //HandlerCallback hCMD; //for CALLBACK function
    HWND hWnd;
}Thread_Info;
//---------------------------------------------------------------------------

UINT StartCOMThread(LPVOID param)
{
    THREAD_INFO *Thread_Info = (THREAD_INFO*)param;
    CRS232_ConnectionDlg *TheDlg = (CRS232_ConnectionDlg*) (Thread_Info->hWnd);
        
    TheDlg->ComReceive(Thread_Info->csCMD);

    return 0;
}
//---------------------------------------------------------------------------


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// Dialog Data
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);             // DDX/DDV support

// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CRS232_ConnectionDlg dialog




CRS232_ConnectionDlg::CRS232_ConnectionDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CRS232_ConnectionDlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CRS232_ConnectionDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_COMBO_ComPort, m_ComPort);
    DDX_Control(pDX, IDC_COMBO_BaudRate, m_BaudRate);
    DDX_Control(pDX, IDC_COMBO_DataBit, m_DataBit);
    DDX_Control(pDX, IDC_COMBO_StopBit, m_StopBit);
    DDX_Control(pDX, IDC_COMBO_Parity, m_Parity);
    DDX_Control(pDX, IDC_COMBO_FlowControl, m_FlowControl);
    DDX_Control(pDX, IDC_CHECK_LineFeed, m_LineFeed);
    DDX_Control(pDX, IDC_Echo, m_Echo);
    DDX_Control(pDX, IDC_CHECK_Recv_LineFeed, m_RecvLineFeed);
    DDX_Control(pDX, IDC_EDIT_SendMessage, m_SendMessage);
    DDX_Control(pDX, IDC_LIST_SendRecvHistory, m_ListSendRecvHistory);
    DDX_Control(pDX, IDC_CHECK_RecvDataAuto, m_RecvAuto);
    DDX_Control(pDX, IDC_BUTTON_Recv, m_BtnRecv);
    DDX_Control(pDX, IDC_STATIC_img, m_ConnectStatusImg);
    DDX_Control(pDX, IDC_BUTTON_Connect, m_BtnConnect);
    DDX_Control(pDX, IDC_BUTTON_Send, m_BtnSend);
}

BEGIN_MESSAGE_MAP(CRS232_ConnectionDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON_Connect, &CRS232_ConnectionDlg::OnBnClickedButtonConnect)
    ON_BN_CLICKED(IDC_BUTTON_Send, &CRS232_ConnectionDlg::OnBnClickedButtonSend)
    ON_BN_CLICKED(IDC_BUTTON_Recv, &CRS232_ConnectionDlg::OnBnClickedButtonRecv)
END_MESSAGE_MAP()


// CRS232_ConnectionDlg message handlers

BOOL CRS232_ConnectionDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.     The framework does this automatically
    //     when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    //List Com Port
    CString csPort;
    for(int i = 1 ; i < 12 ; i++)
    {
        csPort.Format("COM%d", i);
        m_ComPort.AddString(csPort);
    }
    m_ComPort.SetCurSel(0);

    //List Baud Rate
    m_BaudRate.AddString("110");
    m_BaudRate.AddString("300");
    m_BaudRate.AddString("1200");
    m_BaudRate.AddString("2400");
    m_BaudRate.AddString("4800");
    m_BaudRate.AddString("9600");
    m_BaudRate.AddString("19200");
    m_BaudRate.AddString("38400");
    m_BaudRate.AddString("57600");
    m_BaudRate.AddString("115200");
    m_BaudRate.AddString("230400");
    m_BaudRate.AddString("460800");
    m_BaudRate.AddString("921600");
    m_BaudRate.SetCurSel(5);

    //List Data Bit
    m_DataBit.AddString("7");
    m_DataBit.AddString("8");
    m_DataBit.SetCurSel(0);

    //List Stop Bit
    m_StopBit.AddString("1");
    m_StopBit.AddString("1.5");
    m_StopBit.AddString("2");
    m_StopBit.SetCurSel(0);

    //List Parity
    m_Parity.AddString("No parity");
    m_Parity.AddString("Odd");
    m_Parity.AddString("Even");
    m_Parity.AddString("Mark");
    m_Parity.AddString("Space");
    m_Parity.SetCurSel(0);

    //List Flow Control
    m_FlowControl.AddString("Hardware");
    m_FlowControl.AddString("Xon/Xoff");
    m_FlowControl.AddString("None");
    m_FlowControl.SetCurSel(0);

    //Insert ListControl Column
    m_ListSendRecvHistory.InsertColumn(0,"<->",LVCFMT_LEFT,40);
    m_ListSendRecvHistory.InsertColumn(1,"Time",LVCFMT_LEFT,120);
    m_ListSendRecvHistory.InsertColumn(2,"Message",LVCFMT_LEFT,240);
    
    m_RecvAuto.SetCheck(true);

    return TRUE;     // return TRUE     unless you set the focus to a control
}

void CRS232_ConnectionDlg::EnableCOMSetting(bool enable)
{
    m_ComPort.EnableWindow(enable);
    m_BaudRate.EnableWindow(enable);
    m_DataBit.EnableWindow(enable);
    m_StopBit.EnableWindow(enable);
    m_Parity.EnableWindow(enable);
    m_FlowControl.EnableWindow(enable);
    m_LineFeed.EnableWindow(enable);
    m_RecvLineFeed.EnableWindow(enable);
    m_BtnSend.EnableWindow(!enable);
    m_RecvAuto.EnableWindow(enable);
}

bool CRS232_ConnectionDlg::ComOpen(int iComNo, int iBaudRate, int iDataBit, 
                         int iStopBit, int iParityCheck)
{
    if(m_hComm != NULL)
        ComClose();

    iComNo++;

    if(iComNo < 1 && iComNo > 10)
        iComNo = 1;

    switch(iBaudRate)
    {
        case 0:
            iBaudRate = 110;
            break;
        case 1:
            iBaudRate = 300;
            break;
        case 2:
            iBaudRate = 1200;
            break;
        case 3:
            iBaudRate = 2400;
            break;
        case 4:
            iBaudRate = 4800;
            break;
        case 5:
            iBaudRate = 9600;
            break;
        case 6:
            iBaudRate = 19200;
            break;
        case 7:
            iBaudRate = 38400;
            break;
        case 8:
            iBaudRate = 57600;
            break;
        case 9:
            iBaudRate = 115200;
            break;
        case 10:
            iBaudRate = 230400;
            break;
        case 11:
            iBaudRate = 460800;
            break;
        case 12:
            iBaudRate = 921600;
            break;
        default:
            iBaudRate = 9600;
            break;
    }

    switch(iDataBit)
    {
        case 0:
            iDataBit = 7;
            break;
        default:
            iDataBit = 8;
            break;
    }

    DCB PortDCB;
    COMMTIMEOUTS CommTimeouts;
    CString cs;

    cs.Format("COM%d", iComNo);

    // Open the serial port.
    m_hComm = CreateFile(cs, // Pointer to the name of the port
        GENERIC_READ | GENERIC_WRITE, // Access (read/write) mode
        0,                                             // Share mode
        NULL,                                 // Pointer to the security attribute
        OPEN_EXISTING,// How to open the serial port
        0,                                             // Port attributes
        NULL);                             // Handle to port with attribute


    if(m_hComm == INVALID_HANDLE_VALUE) 
    {
        MessageBox("Open com port fails.","Error",
                                         MB_ICONERROR | MB_OK);
        return FALSE;
    }
    
    PortDCB.DCBlength = sizeof (DCB);                 
    
    // Get the default port setting information.
    GetCommState (m_hComm, &PortDCB);
    

    // Change the DCB structure settings.
    PortDCB.BaudRate = iBaudRate;                // Current baud 
    PortDCB.ByteSize = iDataBit;                // Number of bits/bytes, 4-8 
    PortDCB.Parity = iParityCheck;                // 0-4=no,odd,even,mark,space 
    PortDCB.StopBits = iStopBit;                // 0,1,2 = 1, 1.5, 2 
    
    if(iParityCheck > 0)
        PortDCB.fParity = TRUE;                             // Enable parity checking. 
    else
        PortDCB.fParity = FALSE;                                                             // Disable parity checking. 

    PortDCB.fBinary = FALSE;                                                                             // Binary mode; no EOF check 
    PortDCB.fOutxCtsFlow = FALSE;                                                         // No CTS output flow control 
    PortDCB.fOutxDsrFlow = FALSE;                                                         // No DSR output flow control 
    PortDCB.fDtrControl = DTR_CONTROL_DISABLE;     // DTR flow control type 
    PortDCB.fDsrSensitivity = FALSE;                     // DSR sensitivity 
    PortDCB.fTXContinueOnXoff = FALSE;             // XOFF continues Tx 
    PortDCB.fOutX = FALSE;                                                             // No XON/XOFF out flow control 
    PortDCB.fInX = FALSE;                                                                 // No XON/XOFF in flow control 
    PortDCB.fErrorChar = FALSE;                                         // Disable error replacement. 
    PortDCB.fNull = TRUE;                                                                 // Disable null stripping. 
    PortDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;//RTS_CONTROL_DISABLE;     // RTS flow control 
    PortDCB.fAbortOnError = FALSE;                             // Do not abort reads/writes on error.


    // Configure the port according to the specifications of the DCB structure.
    if (!SetCommState (m_hComm, &PortDCB))
    {
        MessageBox("Setting com DCB structure fails.","Error",
                                         MB_ICONERROR | MB_OK);
        ComClose();
        return false;
    }

    // Retrieve the time-out parameters for all read and write operations on the port. 
    GetCommTimeouts(m_hComm, &CommTimeouts);
    
    // Change the COMMTIMEOUTS structure settings.
    CommTimeouts.ReadIntervalTimeout = MAXDWORD;     
    CommTimeouts.ReadTotalTimeoutMultiplier = 0;     
    CommTimeouts.ReadTotalTimeoutConstant = 0;             
    CommTimeouts.WriteTotalTimeoutMultiplier = 10;    // 10     
    CommTimeouts.WriteTotalTimeoutConstant = 1000;        // 1000             
    
    // Set the time-out parameters for all read and write operations on the port. 
    if (!SetCommTimeouts(m_hComm, &CommTimeouts))
    {
        MessageBox("Setting com timeout parameters fails.","Error",
                                         MB_ICONERROR | MB_OK);
        ComClose();
        return false;
    }

    EscapeCommFunction(m_hComm, SETDTR);
    EscapeCommFunction(m_hComm, SETRTS);        

    ComClear();
    
    return true;
}
bool CRS232_ConnectionDlg::IsComOpen()
{
    if(m_hComm != NULL)
        return true;
    else
        return false;
}

bool CRS232_ConnectionDlg::ComSend(char *buffer, int iSize)
{
    unsigned long iLength = 0;

    int iErrorCount=0;
    bool status = true;
    
    while(WriteFile(m_hComm, buffer, iSize, &iLength, NULL) == 0)
    {
        //retransmission
        iErrorCount++;
        if(iErrorCount>5)
        {
            status = false;
            break;
        }
        Sleep(100);
    }
    return status;
}
//---------------------------------------------------------------------------
bool CRS232_ConnectionDlg::ComReceive(CString &recvData)
{
    bool bResult;
    while(IsComOpen())
    {
        unsigned long ulNumRead = 0;
        char *buffer=new char[128];
        

        memset(buffer,0,128);
        bResult = ::ReadFile(m_hComm,buffer, 128, &ulNumRead, NULL);
        if (!bResult && ulNumRead == 0)
            bResult = false;
        else 
            recvData.Format("%s",buffer);

        delete [] buffer;

        if(!bResult)
        {
            break;
        }
        Sleep(50);
    }
    return bResult;
}
//---------------------------------------------------------------------------    
void CRS232_ConnectionDlg::ComClear()
{
    PurgeComm(m_hComm, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
}
//---------------------------------------------------------------------------    
bool CRS232_ConnectionDlg::ComClose()
{
    if(m_hComm == INVALID_HANDLE_VALUE || m_hComm == NULL)
    {
        m_hComm = NULL;
        return true;
    }

    bool b = ::CloseHandle(m_hComm) == 0 ? false : true;
    if(b)
        m_hComm = NULL;

    return b;
}


void CRS232_ConnectionDlg::OnBnClickedButtonConnect()
{
    if(m_LineFeed.GetCheck())
    {
        //Line Feed            LF            \n
        //Carriage Return    CR            \r
        csLineFeed = "\n";
        csCarrierReture = "\r";
    }
    else
    {
        csLineFeed = "";
        csCarrierReture = "";
    }

    if(m_Echo.GetCheck())
    {
        bEcho = true;
    }
    else
        bEcho = false;

    if(m_RecvLineFeed.GetCheck())
    {
        csRecvLineFeed = "\n\r";
    }
    else
    {
        csRecvLineFeed = "";
    }


    //++++++++++Setting UI++++++++++
    if(m_RecvAuto.GetCheck())
        bAutoRecv = true;
    else
        bAutoRecv = false;

    m_BtnRecv.ShowWindow(!bAutoRecv);

    time_t    tSysTime;
    struct    tm* ptm_time;
    char    bufTime[2048];

    time(&tSysTime);
    ptm_time = localtime(&tSysTime);

    strftime(bufTime, sizeof(bufTime), "%Y/%m/%d %H:%M:%S\n", ptm_time);
    m_ListSendRecvHistory.InsertItem(0,"<->");
    //----------Setting UI----------



    CString csBtnCaption;
    m_BtnConnect.GetWindowTextA(csBtnCaption);
    CBitmap    ResultPic;
    if(csBtnCaption == "Connect")
    {
        //++++++++++Connect to RS232++++++++++

        bool status;
        CString csMsg="";

        status = ComOpen(     m_ComPort.GetCurSel(),        //ComNo
                                 m_BaudRate.GetCurSel(),        //BaudRate
                                 m_DataBit.GetCurSel(),        //DataBit
                                 m_StopBit.GetCurSel(),        //StopBit
                                 m_Parity.GetCurSel()            //ParityCheck
                        );

        //----------Connect to RS232----------
        if(status)
        {
            ResultPic.LoadBitmapA(IDB_BITMAP_CONNECT);
            m_ConnectStatusImg.SetBitmap(HBITMAP(ResultPic));
            m_BtnConnect.SetWindowTextA("Disconnect");
            EnableCOMSetting(false);
            m_ListSendRecvHistory.SetItemText(0,1,bufTime);
            m_ListSendRecvHistory.SetItemText(0,2,"Connect");
        }
        else
        {
            m_ListSendRecvHistory.SetItemText(0,1,bufTime);
            m_ListSendRecvHistory.SetItemText(0,2,"Connect Fail");
        }
    }
    else if(csBtnCaption == "Disconnect")
    {
        //++++++++++Disconnect RS232++++++++++

        bool status = ComClose();

        //----------Disconnect RS232----------

        if(status)
        {
            ResultPic.LoadBitmapA(IDB_BITMAP_DISCONNECT);
            m_ConnectStatusImg.SetBitmap(HBITMAP(ResultPic));
            m_BtnConnect.SetWindowTextA("Connect");
            EnableCOMSetting(true);
            m_ListSendRecvHistory.SetItemText(0,1,bufTime);
            m_ListSendRecvHistory.SetItemText(0,2,"Disconnect");
        }
        else
        {
            m_ListSendRecvHistory.SetItemText(0,1,bufTime);
            m_ListSendRecvHistory.SetItemText(0,2,"Disconnect Fail");
        }
    }
    
}

void CRS232_ConnectionDlg::OnBnClickedButtonSend()
{
    CString csMessage;
    
    time_t    tSysTime;
    struct    tm* ptm_time;
    char    bufTime[2048];

    time(&tSysTime);
    ptm_time = localtime(&tSysTime);

    strftime(bufTime, sizeof(bufTime), "%Y/%m/%d %H:%M:%S\n", ptm_time);

    m_SendMessage.GetWindowTextA(csMessage);
    m_ListSendRecvHistory.InsertItem(0,"     ->");
    m_ListSendRecvHistory.SetItemText(0,1,bufTime);
    m_ListSendRecvHistory.SetItemText(0,2,csMessage+csLineFeed+csCarrierReture);

    if(m_RecvAuto.GetCheck())
        bAutoRecv = true;
    else
        bAutoRecv = false;

    m_BtnRecv.ShowWindow(!bAutoRecv);
}

void CRS232_ConnectionDlg::OnBnClickedButtonRecv()
{
    if(m_hComm != NULL) 
    {
        //Thread_Info.csCMD = csRecvMsg;
        //Thread_Info.hCMD = AddMessage;
        Thread_Info.hWnd = (HWND)theApp.m_hInstance;
        AfxBeginThread(StartCOMThread, (LPVOID)&Thread_Info, THREAD_PRIORITY_NORMAL);
    }
}